2005-04-21 07:31:23

by Dmitry Torokhov

[permalink] [raw]
Subject: [RFC/PATCH 0/22] W1: sysfs, lifetime and other fixes

Hi,

I happened to take a look into drivers/w1 and found there bunch of thigs
that IMO should be changed:

- custom-made refcounting is racy
- lifetime rules need to be better enforced
- family framework is insufficient for many advanced w1 devices
- custom-made hotplug notification over netlink should be removed in favor
of standard hotplug notification
- sysfs attributes have unnecessary prefixes (like w1_master) or not needed
at all (w1_master_pointer)

Please consider series of patches below. Unfortunately I do not have any W1
equipment so it was only compile-tested. Please also note that lifetime and
locking rules were changed on object-by-object base so mid-series some stuff
may appear broken but as far as I can see the end result shoudl work pretty
well.

w1-whitespace.patch
Whitespace fixes.

w1-formatting.patch
Some formatting changes to bring the code in line with CodingStyle
guidelines.

w1-master-attr-group.patch
Use attribute_group to create master device attributes to guarantee
proper cleanup in case of failure. Also, hide most of attribute define
ugliness in macros.

w1-slave-attr-group.patc
Add 2 default attributes "family" and "serial" to slave devices, every
1-Wire slave has them. Use attribute_group to handle. The rest of slave
attributes are left as is - will be dealt with later.

w1-lists-cleanup.patch
List handling cleanup. Most of the list_for_each_safe users don't need
*_safe variant, *_entry variant is better suited in most places. Also,
checking retrieved list element for null is a bit pointless...

w1-drop-owner.patch
Drop owner field from w1_master and w1_slave structures. Just having it
there does not magically fixes lifetime rules.

w1-bus-ops.patch
Cleanup bus operations code:
- have bus operatiions accept w1_master instead of unsigned long and
drop data field from w1_bus_master so the structure can be statically
allocated by driver implementing it;
- rename w1_bus_master to w1_bus_ops to avoid confusion with w1_master;
- separate master registering and allocation so drivers can setup proper
link between private data and master and set useable master's name.

w1-fold-w1-int.patch
Fold w1_int.c into w1.c - there is no point in artificially separating
code for master devices between 2 files.

w1-drop-netlink.patch
Drop custom-made hotplug over netlink notification from w1 core.
Standard hotplug mechanism should work just fine (patch will follow).

w1-drop-control-thread.patch
Drop control thread from w1 core, whatever it does can also be done in
the context of w1_remove_master_device. Also, pin the module when
registering new master device to make sure that w1 core is not unloaded
until last device is gone. This simplifies logic a lot.

w1-move-search-to-io.patch
Move w1_search function to w1_io.c to be with the rest of IO code.

w1-master-drop-attrs.patch
Get rid of unneeded master device attributes:
- 'pointer' and 'attempts' are meaningless for userspace;
- information provided by 'slaves' and 'slave_count' can be gathered
from other sysfs bits;
- w1_slave_found has to be rearranged now that slave_count field is gone.

w1-master-attr-cleanup.patch
Clean-up master attribute implementation:
- drop unnecessary "w1_master" prefix from attribute names;
- do not acquire master->mutex when accessing attributes;
- move attribute code "closer" to the rest of master code.

w1-master-scan-interval.patch
More master attributes changes:
- rename timeout parameter/attribute to scan_interval to better
reflect its purpose;
- make scan_timeout be a per-device attribute and allow changing
it from userspace via sysfs;
- allow changing max_slave_count it from userspace as well.

w1-master-add-ttl-attr.patch
Add slave_ttl attribute to w1 masters.

w1-master-cleanup.patch
Clean-up master device implementation:
- get rid of separate refcount, rely on driver model to enforce
lifetime rules;
- use atomic to generate unique master IDs;
- drop unused fields.

w1-slave-cleanup.patch
Clean-up slave device implementation:
- get rid of separate refcount, rely on driver model to enforce
lifetime rules;
- pin w1 module until slave device is registered with sysfs to make
sure W1 core stays loaded.
- drop 'name' attribute as we already have it in bus_id.

w1-family-cleanup.patch
Clean-up family implementation:
- get rid of w1_family_ops and template attributes in w1_slave
structure and have family drivers create necessary attributes
themselves. There are too many different devices using 1-Wire
interface and it is impossible to fit them all into single
attribute model. If interface unification is needed it can be
done by building cross-bus class hierarchy.
- rename w1_smem to w1_sernum because devices are called Silicon
serial numbers, they have address (ID) but don't have memory
in regular sense.
- rename w1_therm to w1_thermal.

w1-family-is-driver.patch
Convert family into proper device-model drivers:
- embed driver structure into w1_family and register with the
driver core;
- do not try to manually bind slaves to familes, leave it to
the driver core;
- fold w1_family.c into w1.c

w1-device-id.patch
Support for automatic family drivers loading via hotplug:
- allow family drivers support list of families;
- export supported families through MODULE_DEVICE_TABLE.

w1-hotplug.patch
Implement W1 bus hotplug handler. Slave devices will define
FID=%02x (family ID) end SN=%024llX environment variables.

w1-module-attrs.patch
Allow changing w1 module parameters through sysfs, add parameter
descriptions and document them in Documentation/kernel-parameters.txt

Thanks!

--
Dmitry


2005-04-21 07:38:23

by Dmitry Torokhov

[permalink] [raw]
Subject: [RFC/PATCH 2/22] W1: formatting fixes

w1: some formatting changes to bring the code in line with
CodingStyle guidelines.

Signed-off-by: Dmitry Torokhov <[email protected]>
---

dscore.c | 4 +---
w1.c | 21 +++++++++------------
2 files changed, 10 insertions(+), 15 deletions(-)

Index: dtor/drivers/w1/w1.c
===================================================================
--- dtor.orig/drivers/w1/w1.c
+++ dtor/drivers/w1/w1.c
@@ -513,8 +513,7 @@ void w1_slave_found(unsigned long data,
sl->reg_num.crc == tmp->crc) {
set_bit(W1_SLAVE_ACTIVE, (long *)&sl->flags);
break;
- }
- else if (sl->reg_num.family == tmp->family) {
+ } else if (sl->reg_num.family == tmp->family) {
family_found = 1;
break;
}
@@ -522,10 +521,10 @@ void w1_slave_found(unsigned long data,
slave_count++;
}

- if (slave_count == dev->slave_count && rn ) {
- tmp = cpu_to_le64(rn);
- if(((rn >> 56) & 0xff) == w1_calc_crc8((u8 *)&tmp, 7))
- w1_attach_slave_device(dev, (struct w1_reg_num *) &rn);
+ if (slave_count == dev->slave_count && rn) {
+ tmp = cpu_to_le64(rn);
+ if (((rn >> 56) & 0xff) == w1_calc_crc8((u8 *)&tmp, 7))
+ w1_attach_slave_device(dev, (struct w1_reg_num *) &rn);
}

atomic_dec(&dev->refcnt);
@@ -544,8 +543,8 @@ void w1_search(struct w1_master *dev)

desc_bit = 64;

- while (!(id_bit && comp_bit) && !last_device
- && count++ < dev->max_slave_count) {
+ while (!(id_bit && comp_bit) && !last_device &&
+ count++ < dev->max_slave_count) {
last = rn;
rn = 0;

@@ -590,8 +589,7 @@ void w1_search(struct w1_master *dev)
last_family_desc = last_zero;
}

- }
- else
+ } else
search_bit = id_bit;

tmp = search_bit;
@@ -760,8 +758,7 @@ int w1_process(void *data)
kfree (sl);

dev->slave_count--;
- }
- else if (test_bit(W1_SLAVE_ACTIVE, (unsigned long *)&sl->flags))
+ } else if (test_bit(W1_SLAVE_ACTIVE, (unsigned long *)&sl->flags))
sl->ttl = dev->slave_ttl;
}
up(&dev->mutex);
Index: dtor/drivers/w1/dscore.c
===================================================================
--- dtor.orig/drivers/w1/dscore.c
+++ dtor/drivers/w1/dscore.c
@@ -319,10 +319,8 @@ int ds_wait_status(struct ds_device *dev
if (((err > 16) && (buf[0x10] & 0x01)) || count >= 100 || err < 0) {
ds_recv_status(dev, st);
return -1;
- }
- else {
+ } else
return 0;
- }
}

int ds_reset(struct ds_device *dev, struct ds_status *st)

2005-04-21 07:37:57

by Dmitry Torokhov

[permalink] [raw]
Subject: [RFC/PATCH 1/22] W1: whitespace fixes

W1: whitespace fixes.

Signed-off-by: Dmitry Torokhov <[email protected]>
---

Kconfig | 14 +++---
Makefile | 2
ds_w1_bridge.c | 24 +++++-----
dscore.c | 126 ++++++++++++++++++++++++++++-----------------------------
dscore.h | 6 +-
matrox_w1.c | 10 ++--
w1.c | 48 ++++++++++-----------
w1.h | 36 ++++++++--------
w1_family.c | 4 -
w1_family.h | 10 ++--
w1_int.c | 18 ++++----
w1_int.h | 4 -
w1_io.c | 4 -
w1_io.h | 4 -
w1_log.h | 4 -
w1_netlink.h | 4 -
w1_smem.c | 10 ++--
w1_therm.c | 18 ++++----
18 files changed, 173 insertions(+), 173 deletions(-)

Index: dtor/drivers/w1/ds_w1_bridge.c
===================================================================
--- dtor.orig/drivers/w1/ds_w1_bridge.c
+++ dtor/drivers/w1/ds_w1_bridge.c
@@ -1,8 +1,8 @@
/*
- * ds_w1_bridge.c
+ * ds_w1_bridge.c
*
* Copyright (c) 2004 Evgeniy Polyakov <[email protected]>
- *
+ *
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -25,7 +25,7 @@
#include "../w1/w1.h"
#include "../w1/w1_int.h"
#include "dscore.h"
-
+
static struct ds_device *ds_dev;
static struct w1_bus_master *ds_bus_master;

@@ -120,7 +120,7 @@ static u8 ds9490r_reset(unsigned long da
static int __devinit ds_w1_init(void)
{
int err;
-
+
ds_bus_master = kmalloc(sizeof(*ds_bus_master), GFP_KERNEL);
if (!ds_bus_master) {
printk(KERN_ERR "Failed to allocate DS9490R USB<->W1 bus_master structure.\n");
@@ -136,14 +136,14 @@ static int __devinit ds_w1_init(void)

memset(ds_bus_master, 0, sizeof(*ds_bus_master));

- ds_bus_master->data = (unsigned long)ds_dev;
- ds_bus_master->touch_bit = &ds9490r_touch_bit;
- ds_bus_master->read_bit = &ds9490r_read_bit;
- ds_bus_master->write_bit = &ds9490r_write_bit;
- ds_bus_master->read_byte = &ds9490r_read_byte;
- ds_bus_master->write_byte = &ds9490r_write_byte;
- ds_bus_master->read_block = &ds9490r_read_block;
- ds_bus_master->write_block = &ds9490r_write_block;
+ ds_bus_master->data = (unsigned long)ds_dev;
+ ds_bus_master->touch_bit = &ds9490r_touch_bit;
+ ds_bus_master->read_bit = &ds9490r_read_bit;
+ ds_bus_master->write_bit = &ds9490r_write_bit;
+ ds_bus_master->read_byte = &ds9490r_read_byte;
+ ds_bus_master->write_byte = &ds9490r_write_byte;
+ ds_bus_master->read_block = &ds9490r_read_block;
+ ds_bus_master->write_block = &ds9490r_write_block;
ds_bus_master->reset_bus = &ds9490r_reset;

err = w1_add_master_device(ds_bus_master);
Index: dtor/drivers/w1/w1_io.h
===================================================================
--- dtor.orig/drivers/w1/w1_io.h
+++ dtor/drivers/w1/w1_io.h
@@ -1,8 +1,8 @@
/*
- * w1_io.h
+ * w1_io.h
*
* Copyright (c) 2004 Evgeniy Polyakov <[email protected]>
- *
+ *
*
* 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
Index: dtor/drivers/w1/w1_therm.c
===================================================================
--- dtor.orig/drivers/w1/w1_therm.c
+++ dtor/drivers/w1/w1_therm.c
@@ -1,8 +1,8 @@
/*
- * w1_therm.c
+ * w1_therm.c
*
* Copyright (c) 2004 Evgeniy Polyakov <[email protected]>
- *
+ *
*
* 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
@@ -38,7 +38,7 @@ MODULE_AUTHOR("Evgeniy Polyakov <johnpol
MODULE_DESCRIPTION("Driver for 1-wire Dallas network protocol, temperature family.");

static u8 bad_roms[][9] = {
- {0xaa, 0x00, 0x4b, 0x46, 0xff, 0xff, 0x0c, 0x10, 0x87},
+ {0xaa, 0x00, 0x4b, 0x46, 0xff, 0xff, 0x0c, 0x10, 0x87},
{}
};

@@ -63,12 +63,12 @@ static ssize_t w1_therm_read_name(struct
static inline int w1_convert_temp(u8 rom[9])
{
int t, h;
-
+
if (rom[1] == 0)
t = ((s32)rom[0] >> 1)*1000;
else
t = 1000*(-1*(s32)(0x100-rom[0]) >> 1);
-
+
t -= 250;
h = 1000*((s32)rom[7] - (s32)rom[6]);
h /= (s32)rom[7];
@@ -98,7 +98,7 @@ static int w1_therm_check_rom(u8 rom[9])
static ssize_t w1_therm_read_bin(struct kobject *kobj, char *buf, loff_t off, size_t count)
{
struct w1_slave *sl = container_of(container_of(kobj, struct device, kobj),
- struct w1_slave, dev);
+ struct w1_slave, dev);
struct w1_master *dev = sl->master;
u8 rom[9], crc, verdict;
int i, max_trying = 10;
@@ -133,7 +133,7 @@ static ssize_t w1_therm_read_bin(struct
unsigned int tm = 750;

memcpy(&match[1], (u64 *) & sl->reg_num, 8);
-
+
w1_write_block(dev, match, 9);

w1_write_8(dev, W1_CONVERT_TEMP);
@@ -146,7 +146,7 @@ static ssize_t w1_therm_read_bin(struct

if (!w1_reset_bus (dev)) {
w1_write_block(dev, match, 9);
-
+
w1_write_8(dev, W1_READ_SCRATCHPAD);
if ((count = w1_read_block(dev, rom, 9)) != 9) {
dev_warn(&dev->dev, "w1_read_block() returned %d instead of 9.\n", count);
@@ -175,7 +175,7 @@ static ssize_t w1_therm_read_bin(struct

for (i = 0; i < 9; ++i)
count += sprintf(buf + count, "%02x ", sl->rom[i]);
-
+
count += sprintf(buf + count, "t=%d\n", w1_convert_temp(rom));
out:
up(&dev->mutex);
Index: dtor/drivers/w1/w1_netlink.h
===================================================================
--- dtor.orig/drivers/w1/w1_netlink.h
+++ dtor/drivers/w1/w1_netlink.h
@@ -33,13 +33,13 @@ enum w1_netlink_message_types {
W1_MASTER_REMOVE,
};

-struct w1_netlink_msg
+struct w1_netlink_msg
{
__u8 type;
__u8 reserved[3];
union
{
- struct w1_reg_num id;
+ struct w1_reg_num id;
__u64 w1_id;
struct
{
Index: dtor/drivers/w1/dscore.h
===================================================================
--- dtor.orig/drivers/w1/dscore.h
+++ dtor/drivers/w1/dscore.h
@@ -1,8 +1,8 @@
/*
- * dscore.h
+ * dscore.h
*
* Copyright (c) 2004 Evgeniy Polyakov <[email protected]>
- *
+ *
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -122,7 +122,7 @@

struct ds_device
{
- struct usb_device *udev;
+ struct usb_device *udev;
struct usb_interface *intf;

int ep[NUM_EP];
Index: dtor/drivers/w1/w1_int.c
===================================================================
--- dtor.orig/drivers/w1/w1_int.c
+++ dtor/drivers/w1/w1_int.c
@@ -1,8 +1,8 @@
/*
- * w1_int.c
+ * w1_int.c
*
* Copyright (c) 2004 Evgeniy Polyakov <[email protected]>
- *
+ *
*
* 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
@@ -60,13 +60,13 @@ struct w1_master * w1_alloc_dev(u32 id,

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;
+ 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;
dev->slave_ttl = slave_ttl;

atomic_set(&dev->refcnt, 2);
Index: dtor/drivers/w1/Makefile
===================================================================
--- dtor.orig/drivers/w1/Makefile
+++ dtor/drivers/w1/Makefile
@@ -13,7 +13,7 @@ obj-$(CONFIG_W1_MATROX) += matrox_w1.o
obj-$(CONFIG_W1_THERM) += w1_therm.o
obj-$(CONFIG_W1_SMEM) += w1_smem.o

-obj-$(CONFIG_W1_DS9490) += ds9490r.o
+obj-$(CONFIG_W1_DS9490) += ds9490r.o
ds9490r-objs := dscore.o

obj-$(CONFIG_W1_DS9490_BRIDGE) += ds_w1_bridge.o
Index: dtor/drivers/w1/matrox_w1.c
===================================================================
--- dtor.orig/drivers/w1/matrox_w1.c
+++ dtor/drivers/w1/matrox_w1.c
@@ -1,8 +1,8 @@
/*
- * matrox_w1.c
+ * matrox_w1.c
*
* Copyright (c) 2004 Evgeniy Polyakov <[email protected]>
- *
+ *
*
* 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
@@ -59,7 +59,7 @@ static struct pci_driver matrox_w1_pci_d
.remove = __devexit_p(matrox_w1_remove),
};

-/*
+/*
* Matrox G400 DDC registers.
*/

@@ -177,8 +177,8 @@ static int __devinit matrox_w1_probe(str

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
+ /*
+ * 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);
Index: dtor/drivers/w1/w1_smem.c
===================================================================
--- dtor.orig/drivers/w1/w1_smem.c
+++ dtor/drivers/w1/w1_smem.c
@@ -1,8 +1,8 @@
/*
- * w1_smem.c
+ * w1_smem.c
*
* Copyright (c) 2004 Evgeniy Polyakov <[email protected]>
- *
+ *
*
* This program is free software; you can redistribute it and/or modify
* it under the smems of the GNU General Public License as published by
@@ -59,7 +59,7 @@ static ssize_t w1_smem_read_val(struct d
struct w1_slave *sl = container_of(dev, struct w1_slave, dev);
int i;
ssize_t count = 0;
-
+
for (i = 0; i < 9; ++i)
count += sprintf(buf + count, "%02x ", ((u8 *)&sl->reg_num)[i]);
count += sprintf(buf + count, "\n");
@@ -70,7 +70,7 @@ static ssize_t w1_smem_read_val(struct d
static ssize_t w1_smem_read_bin(struct kobject *kobj, char *buf, loff_t off, size_t count)
{
struct w1_slave *sl = container_of(container_of(kobj, struct device, kobj),
- struct w1_slave, dev);
+ struct w1_slave, dev);
int i;

atomic_inc(&sl->refcnt);
@@ -90,7 +90,7 @@ static ssize_t w1_smem_read_bin(struct k
for (i = 0; i < 9; ++i)
count += sprintf(buf + count, "%02x ", ((u8 *)&sl->reg_num)[i]);
count += sprintf(buf + count, "\n");
-
+
out:
up(&sl->master->mutex);
out_dec:
Index: dtor/drivers/w1/w1_family.c
===================================================================
--- dtor.orig/drivers/w1/w1_family.c
+++ dtor/drivers/w1/w1_family.c
@@ -1,8 +1,8 @@
/*
- * w1_family.c
+ * w1_family.c
*
* Copyright (c) 2004 Evgeniy Polyakov <[email protected]>
- *
+ *
*
* 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
Index: dtor/drivers/w1/w1.c
===================================================================
--- dtor.orig/drivers/w1/w1.c
+++ dtor/drivers/w1/w1.c
@@ -1,8 +1,8 @@
/*
- * w1.c
+ * w1.c
*
* Copyright (c) 2004 Evgeniy Polyakov <[email protected]>
- *
+ *
*
* 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
@@ -141,12 +141,12 @@ static ssize_t w1_master_attribute_show_
{
struct w1_master *md = container_of (dev, struct w1_master, dev);
ssize_t count;
-
+
if (down_interruptible (&md->mutex))
return -EBUSY;

count = sprintf(buf, "%s\n", md->name);
-
+
up(&md->mutex);

return count;
@@ -156,12 +156,12 @@ static ssize_t w1_master_attribute_show_
{
struct w1_master *md = container_of(dev, struct w1_master, dev);
ssize_t count;
-
+
if (down_interruptible(&md->mutex))
return -EBUSY;

count = sprintf(buf, "0x%p\n", md->bus_master);
-
+
up(&md->mutex);
return count;
}
@@ -177,12 +177,12 @@ static ssize_t w1_master_attribute_show_
{
struct w1_master *md = container_of(dev, struct w1_master, dev);
ssize_t count;
-
+
if (down_interruptible(&md->mutex))
return -EBUSY;

count = sprintf(buf, "%d\n", md->max_slave_count);
-
+
up(&md->mutex);
return count;
}
@@ -191,12 +191,12 @@ static ssize_t w1_master_attribute_show_
{
struct w1_master *md = container_of(dev, struct w1_master, dev);
ssize_t count;
-
+
if (down_interruptible(&md->mutex))
return -EBUSY;

count = sprintf(buf, "%lu\n", md->attempts);
-
+
up(&md->mutex);
return count;
}
@@ -205,12 +205,12 @@ static ssize_t w1_master_attribute_show_
{
struct w1_master *md = container_of(dev, struct w1_master, dev);
ssize_t count;
-
+
if (down_interruptible(&md->mutex))
return -EBUSY;

count = sprintf(buf, "%d\n", md->slave_count);
-
+
up(&md->mutex);
return count;
}
@@ -233,7 +233,7 @@ static ssize_t w1_master_attribute_show_
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\n", sl->name);
+ c -= snprintf(buf + PAGE_SIZE - c, c, "%s\n", sl->name);
}
}

@@ -244,11 +244,11 @@ static ssize_t w1_master_attribute_show_

static struct device_attribute w1_master_attribute_slaves = {
.attr = {
- .name = "w1_master_slaves",
+ .name = "w1_master_slaves",
.mode = S_IRUGO,
.owner = THIS_MODULE,
},
- .show = &w1_master_attribute_show_slaves,
+ .show = &w1_master_attribute_show_slaves,
};
static struct device_attribute w1_master_attribute_slave_count = {
.attr = {
@@ -301,8 +301,8 @@ static struct device_attribute w1_master

static struct bin_attribute w1_slave_bin_attribute = {
.attr = {
- .name = "w1_slave",
- .mode = S_IRUGO,
+ .name = "w1_slave",
+ .mode = S_IRUGO,
.owner = THIS_MODULE,
},
.size = W1_SLAVE_DATA_SIZE,
@@ -341,7 +341,7 @@ static int __w1_attach_slave_device(stru
memcpy(&sl->attr_bin, &w1_slave_bin_attribute, sizeof(sl->attr_bin));
memcpy(&sl->attr_name, &w1_slave_attribute, sizeof(sl->attr_name));
memcpy(&sl->attr_val, &w1_slave_attribute_val, sizeof(sl->attr_val));
-
+
sl->attr_bin.read = sl->family->fops->rbin;
sl->attr_name.show = sl->family->fops->rname;
sl->attr_val.show = sl->family->fops->rval;
@@ -445,7 +445,7 @@ static int w1_attach_slave_device(struct
static void w1_slave_detach(struct w1_slave *sl)
{
struct w1_netlink_msg msg;
-
+
dev_info(&sl->dev, "%s: detaching %s.\n", __func__, sl->name);

while (atomic_read(&sl->refcnt)) {
@@ -471,7 +471,7 @@ static struct w1_master *w1_search_maste
{
struct w1_master *dev;
int found = 0;
-
+
spin_lock_irq(&w1_mlock);
list_for_each_entry(dev, &w1_masters, w1_master_entry) {
if (dev->bus_master->data == data) {
@@ -500,7 +500,7 @@ void w1_slave_found(unsigned long data,
data);
return;
}
-
+
tmp = (struct w1_reg_num *) &rn;

slave_count = 0;
@@ -527,7 +527,7 @@ void w1_slave_found(unsigned long data,
if(((rn >> 56) & 0xff) == w1_calc_crc8((u8 *)&tmp, 7))
w1_attach_slave_device(dev, (struct w1_reg_num *) &rn);
}
-
+
atomic_dec(&dev->refcnt);
}

@@ -614,7 +614,7 @@ void w1_search(struct w1_master *dev)
last_device = 1;

desc_bit = last_zero;
-
+
w1_slave_found(dev->bus_master->data, rn);
}
}
@@ -747,7 +747,7 @@ int w1_process(void *data)
if (sl)
clear_bit(W1_SLAVE_ACTIVE, (long *)&sl->flags);
}
-
+
w1_search_devices(dev, w1_slave_found);

list_for_each_safe(ent, n, &dev->slist) {
Index: dtor/drivers/w1/w1_log.h
===================================================================
--- dtor.orig/drivers/w1/w1_log.h
+++ dtor/drivers/w1/w1_log.h
@@ -1,8 +1,8 @@
/*
- * w1_log.h
+ * w1_log.h
*
* Copyright (c) 2004 Evgeniy Polyakov <[email protected]>
- *
+ *
*
* 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
Index: dtor/drivers/w1/w1_io.c
===================================================================
--- dtor.orig/drivers/w1/w1_io.c
+++ dtor/drivers/w1/w1_io.c
@@ -1,8 +1,8 @@
/*
- * w1_io.c
+ * w1_io.c
*
* Copyright (c) 2004 Evgeniy Polyakov <[email protected]>
- *
+ *
*
* 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
Index: dtor/drivers/w1/w1_int.h
===================================================================
--- dtor.orig/drivers/w1/w1_int.h
+++ dtor/drivers/w1/w1_int.h
@@ -1,8 +1,8 @@
/*
- * w1_int.h
+ * w1_int.h
*
* Copyright (c) 2004 Evgeniy Polyakov <[email protected]>
- *
+ *
*
* 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
Index: dtor/drivers/w1/w1_family.h
===================================================================
--- dtor.orig/drivers/w1/w1_family.h
+++ dtor/drivers/w1/w1_family.h
@@ -1,8 +1,8 @@
/*
- * w1_family.h
+ * w1_family.h
*
* Copyright (c) 2004 Evgeniy Polyakov <[email protected]>
- *
+ *
*
* 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
@@ -36,7 +36,7 @@ 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];
};
@@ -45,9 +45,9 @@ struct w1_family
{
struct list_head family_entry;
u8 fid;
-
+
struct w1_family_ops *fops;
-
+
atomic_t refcnt;
u8 need_exit;
};
Index: dtor/drivers/w1/dscore.c
===================================================================
--- dtor.orig/drivers/w1/dscore.c
+++ dtor/drivers/w1/dscore.c
@@ -1,8 +1,8 @@
/*
- * dscore.c
+ * dscore.c
*
* Copyright (c) 2004 Evgeniy Polyakov <[email protected]>
- *
+ *
*
* 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
@@ -79,11 +79,11 @@ void ds_put_device(struct ds_device *dev
static int ds_send_control_cmd(struct ds_device *dev, u16 value, u16 index)
{
int err;
-
- err = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, dev->ep[EP_CONTROL]),
+
+ err = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, dev->ep[EP_CONTROL]),
CONTROL_CMD, 0x40, value, index, NULL, 0, 1000);
if (err < 0) {
- printk(KERN_ERR "Failed to send command control message %x.%x: err=%d.\n",
+ printk(KERN_ERR "Failed to send command control message %x.%x: err=%d.\n",
value, index, err);
return err;
}
@@ -94,11 +94,11 @@ static int ds_send_control_cmd(struct ds
static int ds_send_control_mode(struct ds_device *dev, u16 value, u16 index)
{
int err;
-
- err = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, dev->ep[EP_CONTROL]),
+
+ err = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, dev->ep[EP_CONTROL]),
MODE_CMD, 0x40, value, index, NULL, 0, 1000);
if (err < 0) {
- printk(KERN_ERR "Failed to send mode control message %x.%x: err=%d.\n",
+ printk(KERN_ERR "Failed to send mode control message %x.%x: err=%d.\n",
value, index, err);
return err;
}
@@ -109,11 +109,11 @@ static int ds_send_control_mode(struct d
static int ds_send_control(struct ds_device *dev, u16 value, u16 index)
{
int err;
-
- err = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, dev->ep[EP_CONTROL]),
+
+ err = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, dev->ep[EP_CONTROL]),
COMM_CMD, 0x40, value, index, NULL, 0, 1000);
if (err < 0) {
- printk(KERN_ERR "Failed to send control message %x.%x: err=%d.\n",
+ printk(KERN_ERR "Failed to send control message %x.%x: err=%d.\n",
value, index, err);
return err;
}
@@ -129,16 +129,16 @@ static inline void ds_dump_status(unsign
int ds_recv_status_nodump(struct ds_device *dev, struct ds_status *st, unsigned char *buf, int size)
{
int count, err;
-
+
memset(st, 0, sizeof(st));
-
+
count = 0;
err = usb_bulk_msg(dev->udev, usb_rcvbulkpipe(dev->udev, dev->ep[EP_STATUS]), buf, size, &count, 100);
if (err < 0) {
printk(KERN_ERR "Failed to read 1-wire data from 0x%x: err=%d.\n", dev->ep[EP_STATUS], err);
return err;
}
-
+
if (count >= sizeof(*st))
memcpy(st, buf, sizeof(*st));

@@ -149,13 +149,13 @@ static int ds_recv_status(struct ds_devi
{
unsigned char buf[64];
int count, err = 0, i;
-
+
memcpy(st, buf, sizeof(*st));
-
+
count = ds_recv_status_nodump(dev, st, buf, sizeof(buf));
if (count < 0)
return err;
-
+
printk("0x%x: count=%d, status: ", dev->ep[EP_STATUS], count);
for (i=0; i<count; ++i)
printk("%02x ", buf[i]);
@@ -199,7 +199,7 @@ static int ds_recv_status(struct ds_devi
return err;
}
#endif
-
+
return err;
}

@@ -207,9 +207,9 @@ static int ds_recv_data(struct ds_device
{
int count, err;
struct ds_status st;
-
+
count = 0;
- err = usb_bulk_msg(dev->udev, usb_rcvbulkpipe(dev->udev, dev->ep[EP_DATA_IN]),
+ err = usb_bulk_msg(dev->udev, usb_rcvbulkpipe(dev->udev, dev->ep[EP_DATA_IN]),
buf, size, &count, 1000);
if (err < 0) {
printk(KERN_INFO "Clearing ep0x%x.\n", dev->ep[EP_DATA_IN]);
@@ -234,7 +234,7 @@ static int ds_recv_data(struct ds_device
static int ds_send_data(struct ds_device *dev, unsigned char *buf, int len)
{
int count, err;
-
+
count = 0;
err = usb_bulk_msg(dev->udev, usb_sndbulkpipe(dev->udev, dev->ep[EP_DATA_OUT]), buf, len, &count, 1000);
if (err < 0) {
@@ -250,7 +250,7 @@ int ds_stop_pulse(struct ds_device *dev,
struct ds_status st;
int count = 0, err = 0;
u8 buf[0x20];
-
+
do {
err = ds_send_control(dev, CTL_HALT_EXE_IDLE, 0);
if (err)
@@ -275,7 +275,7 @@ int ds_stop_pulse(struct ds_device *dev,
int ds_detect(struct ds_device *dev, struct ds_status *st)
{
int err;
-
+
err = ds_send_control_cmd(dev, CTL_RESET_DEVICE, 0);
if (err)
return err;
@@ -283,11 +283,11 @@ int ds_detect(struct ds_device *dev, str
err = ds_send_control(dev, COMM_SET_DURATION | COMM_IM, 0);
if (err)
return err;
-
+
err = ds_send_control(dev, COMM_SET_DURATION | COMM_IM | COMM_TYPE, 0x40);
if (err)
return err;
-
+
err = ds_send_control_mode(dev, MOD_PULSE_EN, PULSE_PROG);
if (err)
return err;
@@ -305,7 +305,7 @@ int ds_wait_status(struct ds_device *dev
do {
err = ds_recv_status_nodump(dev, st, buf, sizeof(buf));
#if 0
- if (err >= 0) {
+ if (err >= 0) {
int i;
printk("0x%x: count=%d, status: ", dev->ep[EP_STATUS], err);
for (i=0; i<err; ++i)
@@ -341,14 +341,14 @@ int ds_reset(struct ds_device *dev, stru
return -EIO;
}
#endif
-
+
return 0;
}

int ds_set_speed(struct ds_device *dev, int speed)
{
int err;
-
+
if (speed != SPEED_NORMAL && speed != SPEED_FLEXIBLE && speed != SPEED_OVERDRIVE)
return -EINVAL;

@@ -356,7 +356,7 @@ int ds_set_speed(struct ds_device *dev,
speed = SPEED_FLEXIBLE;

speed &= 0xff;
-
+
err = ds_send_control_mode(dev, MOD_1WIRE_SPEED, speed);
if (err)
return err;
@@ -369,7 +369,7 @@ int ds_start_pulse(struct ds_device *dev
int err;
u8 del = 1 + (u8)(delay >> 4);
struct ds_status st;
-
+
#if 0
err = ds_stop_pulse(dev, 10);
if (err)
@@ -390,7 +390,7 @@ int ds_start_pulse(struct ds_device *dev
mdelay(delay);

ds_wait_status(dev, &st);
-
+
return err;
}

@@ -400,7 +400,7 @@ int ds_touch_bit(struct ds_device *dev,
struct ds_status st;
u16 value = (COMM_BIT_IO | COMM_IM) | ((bit) ? COMM_D : 0);
u16 cmd;
-
+
err = ds_send_control(dev, value, 0);
if (err)
return err;
@@ -430,7 +430,7 @@ int ds_write_bit(struct ds_device *dev,
{
int err;
struct ds_status st;
-
+
err = ds_send_control(dev, COMM_BIT_IO | COMM_IM | (bit) ? COMM_D : 0, 0);
if (err)
return err;
@@ -445,7 +445,7 @@ int ds_write_byte(struct ds_device *dev,
int err;
struct ds_status st;
u8 rbyte;
-
+
err = ds_send_control(dev, COMM_BYTE_IO | COMM_IM | COMM_SPU, byte);
if (err)
return err;
@@ -453,11 +453,11 @@ int ds_write_byte(struct ds_device *dev,
err = ds_wait_status(dev, &st);
if (err)
return err;
-
+
err = ds_recv_data(dev, &rbyte, sizeof(rbyte));
if (err < 0)
return err;
-
+
ds_start_pulse(dev, PULLUP_PULSE_DURATION);

return !(byte == rbyte);
@@ -470,11 +470,11 @@ int ds_read_bit(struct ds_device *dev, u
err = ds_send_control_mode(dev, MOD_PULSE_EN, PULSE_SPUE);
if (err)
return err;
-
+
err = ds_send_control(dev, COMM_BIT_IO | COMM_IM | COMM_SPU | COMM_D, 0);
if (err)
return err;
-
+
err = ds_recv_data(dev, bit, sizeof(*bit));
if (err < 0)
return err;
@@ -492,7 +492,7 @@ int ds_read_byte(struct ds_device *dev,
return err;

ds_wait_status(dev, &st);
-
+
err = ds_recv_data(dev, byte, sizeof(*byte));
if (err < 0)
return err;
@@ -509,17 +509,17 @@ int ds_read_block(struct ds_device *dev,
return -E2BIG;

memset(buf, 0xFF, len);
-
+
err = ds_send_data(dev, buf, len);
if (err < 0)
return err;
-
+
err = ds_send_control(dev, COMM_BLOCK_IO | COMM_IM | COMM_SPU, len);
if (err)
return err;

ds_wait_status(dev, &st);
-
+
memset(buf, 0x00, len);
err = ds_recv_data(dev, buf, len);

@@ -530,11 +530,11 @@ int ds_write_block(struct ds_device *dev
{
int err;
struct ds_status st;
-
+
err = ds_send_data(dev, buf, len);
if (err < 0)
return err;
-
+
ds_wait_status(dev, &st);

err = ds_send_control(dev, COMM_BLOCK_IO | COMM_IM | COMM_SPU, len);
@@ -548,7 +548,7 @@ int ds_write_block(struct ds_device *dev
return err;

ds_start_pulse(dev, PULLUP_PULSE_DURATION);
-
+
return !(err == len);
}

@@ -559,11 +559,11 @@ int ds_search(struct ds_device *dev, u64
struct ds_status st;

memset(buf, 0, sizeof(buf));
-
+
err = ds_send_data(ds_dev, (unsigned char *)&init, 8);
if (err)
return err;
-
+
ds_wait_status(ds_dev, &st);

value = COMM_SEARCH_ACCESS | COMM_IM | COMM_SM | COMM_F | COMM_RTS;
@@ -589,7 +589,7 @@ int ds_match_access(struct ds_device *de
err = ds_send_data(dev, (unsigned char *)&init, sizeof(init));
if (err)
return err;
-
+
ds_wait_status(dev, &st);

err = ds_send_control(dev, COMM_MATCH_ACCESS | COMM_IM | COMM_RST, 0x0055);
@@ -609,11 +609,11 @@ int ds_set_path(struct ds_device *dev, u

memcpy(buf, &init, 8);
buf[8] = BRANCH_MAIN;
-
+
err = ds_send_data(dev, buf, sizeof(buf));
if (err)
return err;
-
+
ds_wait_status(dev, &st);

err = ds_send_control(dev, COMM_SET_PATH | COMM_IM | COMM_RST, 0);
@@ -653,7 +653,7 @@ int ds_probe(struct usb_interface *intf,
printk(KERN_ERR "Failed to reset configuration: err=%d.\n", err);
return err;
}
-
+
iface_desc = &intf->altsetting[0];
if (iface_desc->desc.bNumEndpoints != NUM_EP-1) {
printk(KERN_INFO "Num endpoints=%d. It is not DS9490R.\n", iface_desc->desc.bNumEndpoints);
@@ -662,37 +662,37 @@ int ds_probe(struct usb_interface *intf,

atomic_set(&ds_dev->refcnt, 0);
memset(ds_dev->ep, 0, sizeof(ds_dev->ep));
-
+
/*
- * This loop doesn'd show control 0 endpoint,
+ * This loop doesn'd show control 0 endpoint,
* so we will fill only 1-3 endpoints entry.
*/
for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
endpoint = &iface_desc->endpoint[i].desc;

ds_dev->ep[i+1] = endpoint->bEndpointAddress;
-
+
printk("%d: addr=%x, size=%d, dir=%s, type=%x\n",
i, endpoint->bEndpointAddress, le16_to_cpu(endpoint->wMaxPacketSize),
(endpoint->bEndpointAddress & USB_DIR_IN)?"IN":"OUT",
endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK);
}
-
+
#if 0
{
int err, i;
u64 buf[3];
u64 init=0xb30000002078ee81ull;
struct ds_status st;
-
+
ds_reset(ds_dev, &st);
err = ds_search(ds_dev, init, buf, 3, 0);
if (err < 0)
return err;
for (i=0; i<err; ++i)
printk("%d: %llx\n", i, buf[i]);
-
- printk("Resetting...\n");
+
+ printk("Resetting...\n");
ds_reset(ds_dev, &st);
printk("Setting path for %llx.\n", init);
err = ds_set_path(ds_dev, init);
@@ -707,12 +707,12 @@ int ds_probe(struct usb_interface *intf,
err = ds_search(ds_dev, init, buf, 3, 0);

printk("ds_search() returned %d\n", err);
-
+
if (err < 0)
return err;
for (i=0; i<err; ++i)
printk("%d: %llx\n", i, buf[i]);
-
+
return 0;
}
#endif
@@ -723,7 +723,7 @@ int ds_probe(struct usb_interface *intf,
void ds_disconnect(struct usb_interface *intf)
{
struct ds_device *dev;
-
+
dev = usb_get_intfdata(intf);
usb_set_intfdata(intf, NULL);

@@ -776,8 +776,8 @@ EXPORT_SYMBOL(ds_get_device);
EXPORT_SYMBOL(ds_put_device);

/*
- * This functions can be used for EEPROM programming,
- * when driver will be included into mainline this will
+ * This functions can be used for EEPROM programming,
+ * when driver will be included into mainline this will
* require uncommenting.
*/
#if 0
Index: dtor/drivers/w1/w1.h
===================================================================
--- dtor.orig/drivers/w1/w1.h
+++ dtor/drivers/w1/w1.h
@@ -1,8 +1,8 @@
/*
- * w1.h
+ * w1.h
*
* Copyright (c) 2004 Evgeniy Polyakov <[email protected]>
- *
+ *
*
* 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
@@ -74,11 +74,11 @@ struct w1_slave
int ttl;

struct w1_master *master;
- struct w1_family *family;
- struct device dev;
- struct completion dev_released;
+ struct w1_family *family;
+ struct device dev;
+ struct completion dev_released;

- struct bin_attribute attr_bin;
+ struct bin_attribute attr_bin;
struct device_attribute attr_name, attr_val;
};

@@ -90,16 +90,16 @@ struct w1_bus_master

u8 (*read_bit)(unsigned long);
void (*write_bit)(unsigned long, u8);
-
+
u8 (*read_byte)(unsigned long);
- void (*write_byte)(unsigned long, u8);
-
+ void (*write_byte)(unsigned long, u8);
+
u8 (*read_block)(unsigned long, u8 *, int);
void (*write_block)(unsigned long, u8 *, int);
-
- u8 (*touch_bit)(unsigned long, u8);
-
- u8 (*reset_bus)(unsigned long);
+
+ u8 (*touch_bit)(unsigned long, u8);
+
+ u8 (*reset_bus)(unsigned long);

void (*search)(unsigned long, w1_slave_found_callback);
};
@@ -123,17 +123,17 @@ struct w1_master

int need_exit;
pid_t kpid;
- struct semaphore mutex;
+ struct semaphore mutex;

struct device_driver *driver;
- struct device dev;
- struct completion dev_released;
- struct completion dev_exited;
+ struct device dev;
+ struct completion dev_released;
+ struct completion dev_exited;

struct w1_bus_master *bus_master;

u32 seq, groups;
- struct sock *nls;
+ struct sock *nls;
};

int w1_create_master_attributes(struct w1_master *);
Index: dtor/drivers/w1/Kconfig
===================================================================
--- dtor.orig/drivers/w1/Kconfig
+++ dtor/drivers/w1/Kconfig
@@ -3,9 +3,9 @@ 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
+ 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
@@ -17,8 +17,8 @@ config W1_MATROX
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
+
+ This support is also available as a module. If so, the module
will be called matrox_w1.ko.

config W1_DS9490
@@ -27,7 +27,7 @@ config W1_DS9490
help
Say Y here if you want to have a driver for DS9490R UWB <-> W1 bridge.

- This support is also available as a module. If so, the module
+ This support is also available as a module. If so, the module
will be called ds9490r.ko.

config W1_DS9490_BRIDGE
@@ -37,7 +37,7 @@ config W1_DS9490_BRIDGE
Say Y here if you want to communicate with your 1-wire devices
using DS9490R USB bridge.

- This support is also available as a module. If so, the module
+ This support is also available as a module. If so, the module
will be called ds_w1_bridge.ko.

config W1_THERM
@@ -51,7 +51,7 @@ config W1_SMEM
tristate "Simple 64bit memory family implementation"
depends on W1
help
- Say Y here if you want to connect 1-wire
+ Say Y here if you want to connect 1-wire
simple 64bit memory rom(ds2401/ds2411/ds1990*) to you wire.

endmenu

2005-04-21 07:41:20

by Dmitry Torokhov

[permalink] [raw]
Subject: [RFC/PATCH 3/22] W1: use attribute group for master's attributes

W1: use attribute_group to create master device attributes to
guarantee proper cleanup in case of failure. Also, hide
most of attribute define ugliness in macros.

Signed-off-by: Dmitry Torokhov <[email protected]>
---

w1.c | 157 +++++++++++++++++++++----------------------------------------------
1 files changed, 51 insertions(+), 106 deletions(-)

Index: dtor/drivers/w1/w1.c
===================================================================
--- dtor.orig/drivers/w1/w1.c
+++ dtor/drivers/w1/w1.c
@@ -99,6 +99,23 @@ static ssize_t w1_default_read_bin(struc
return sprintf(buf, "No family registered.\n");
}

+static struct device_attribute w1_slave_attribute =
+ __ATTR(name, S_IRUGO, w1_default_read_name, NULL);
+
+static struct device_attribute w1_slave_attribute_val =
+ __ATTR(value, S_IRUGO, w1_default_read_name, NULL);
+
+static struct bin_attribute w1_slave_bin_attribute = {
+ .attr = {
+ .name = "w1_slave",
+ .mode = S_IRUGO,
+ .owner = THIS_MODULE,
+ },
+ .size = W1_SLAVE_DATA_SIZE,
+ .read = &w1_default_read_bin,
+};
+
+
static struct bus_type w1_bus_type = {
.name = "w1",
.match = w1_master_match,
@@ -119,24 +136,6 @@ struct device w1_device = {
.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,
-};
-
static ssize_t w1_master_attribute_show_name(struct device *dev, char *buf)
{
struct w1_master *md = container_of (dev, struct w1_master, dev);
@@ -242,73 +241,44 @@ static ssize_t w1_master_attribute_show_
return PAGE_SIZE - c;
}

-static struct device_attribute w1_master_attribute_slaves = {
- .attr = {
- .name = "w1_master_slaves",
- .mode = S_IRUGO,
- .owner = THIS_MODULE,
- },
- .show = &w1_master_attribute_show_slaves,
-};
-static struct device_attribute w1_master_attribute_slave_count = {
- .attr = {
- .name = "w1_master_slave_count",
- .mode = S_IRUGO,
- .owner = THIS_MODULE
- },
- .show = &w1_master_attribute_show_slave_count,
-};
-static struct device_attribute w1_master_attribute_attempts = {
- .attr = {
- .name = "w1_master_attempts",
- .mode = S_IRUGO,
- .owner = THIS_MODULE
- },
- .show = &w1_master_attribute_show_attempts,
-};
-static struct device_attribute w1_master_attribute_max_slave_count = {
- .attr = {
- .name = "w1_master_max_slave_count",
- .mode = S_IRUGO,
- .owner = THIS_MODULE
- },
- .show = &w1_master_attribute_show_max_slave_count,
-};
-static struct device_attribute w1_master_attribute_timeout = {
- .attr = {
- .name = "w1_master_timeout",
- .mode = S_IRUGO,
- .owner = THIS_MODULE
- },
- .show = &w1_master_attribute_show_timeout,
-};
-static struct device_attribute w1_master_attribute_pointer = {
- .attr = {
- .name = "w1_master_pointer",
- .mode = S_IRUGO,
- .owner = THIS_MODULE
- },
- .show = &w1_master_attribute_show_pointer,
-};
-static struct device_attribute w1_master_attribute_name = {
- .attr = {
- .name = "w1_master_name",
- .mode = S_IRUGO,
- .owner = THIS_MODULE
- },
- .show = &w1_master_attribute_show_name,
+#define W1_MASTER_ATTR_RO(_name, _mode) \
+ struct device_attribute w1_master_attribute_##_name = \
+ __ATTR(w1_master_##_name, _mode, \
+ w1_master_attribute_show_##_name, NULL)
+
+static W1_MASTER_ATTR_RO(name, S_IRUGO);
+static W1_MASTER_ATTR_RO(slaves, S_IRUGO);
+static W1_MASTER_ATTR_RO(slave_count, S_IRUGO);
+static W1_MASTER_ATTR_RO(max_slave_count, S_IRUGO);
+static W1_MASTER_ATTR_RO(attempts, S_IRUGO);
+static W1_MASTER_ATTR_RO(timeout, S_IRUGO);
+static W1_MASTER_ATTR_RO(pointer, S_IRUGO);
+
+static struct attribute *w1_master_default_attrs[] = {
+ &w1_master_attribute_name.attr,
+ &w1_master_attribute_slaves.attr,
+ &w1_master_attribute_slave_count.attr,
+ &w1_master_attribute_max_slave_count.attr,
+ &w1_master_attribute_attempts.attr,
+ &w1_master_attribute_timeout.attr,
+ &w1_master_attribute_pointer.attr,
+ NULL
};

-static struct bin_attribute w1_slave_bin_attribute = {
- .attr = {
- .name = "w1_slave",
- .mode = S_IRUGO,
- .owner = THIS_MODULE,
- },
- .size = W1_SLAVE_DATA_SIZE,
- .read = &w1_default_read_bin,
+static struct attribute_group w1_master_defattr_group = {
+ .attrs = w1_master_default_attrs,
};

+int w1_create_master_attributes(struct w1_master *master)
+{
+ return sysfs_create_group(&master->dev.kobj, &w1_master_defattr_group);
+}
+
+void w1_destroy_master_attributes(struct w1_master *master)
+{
+ sysfs_remove_group(&master->dev.kobj, &w1_master_defattr_group);
+}
+
static int __w1_attach_slave_device(struct w1_slave *sl)
{
int err;
@@ -617,31 +587,6 @@ void w1_search(struct w1_master *dev)
}
}

-int w1_create_master_attributes(struct w1_master *dev)
-{
- if ( device_create_file(&dev->dev, &w1_master_attribute_slaves) < 0 ||
- device_create_file(&dev->dev, &w1_master_attribute_slave_count) < 0 ||
- device_create_file(&dev->dev, &w1_master_attribute_attempts) < 0 ||
- device_create_file(&dev->dev, &w1_master_attribute_max_slave_count) < 0 ||
- device_create_file(&dev->dev, &w1_master_attribute_timeout) < 0||
- device_create_file(&dev->dev, &w1_master_attribute_pointer) < 0||
- device_create_file(&dev->dev, &w1_master_attribute_name) < 0)
- return -EINVAL;
-
- return 0;
-}
-
-void w1_destroy_master_attributes(struct w1_master *dev)
-{
- device_remove_file(&dev->dev, &w1_master_attribute_slaves);
- device_remove_file(&dev->dev, &w1_master_attribute_slave_count);
- device_remove_file(&dev->dev, &w1_master_attribute_attempts);
- device_remove_file(&dev->dev, &w1_master_attribute_max_slave_count);
- device_remove_file(&dev->dev, &w1_master_attribute_timeout);
- device_remove_file(&dev->dev, &w1_master_attribute_pointer);
- device_remove_file(&dev->dev, &w1_master_attribute_name);
-}
-

int w1_control(void *data)
{

2005-04-21 07:41:18

by Dmitry Torokhov

[permalink] [raw]
Subject: [RFC/PATCH 4/22] W1: use attribute group for slave's attributes

W1: add 2 default attributes "family" and "serial" to slave
devices, every 1-Wire slave has them. Use attribute_group
to handle. The rest of slave attributes are left as is -
will be dealt with later.

Signed-off-by: Dmitry Torokhov <[email protected]>
---

w1.c | 115 ++++++++++++++++++++++++++++++++++++++++++++++---------------------
w1.h | 1
2 files changed, 81 insertions(+), 35 deletions(-)

Index: dtor/drivers/w1/w1.c
===================================================================
--- dtor.orig/drivers/w1/w1.c
+++ dtor/drivers/w1/w1.c
@@ -81,40 +81,6 @@ static void w1_master_release(struct 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");
-}
-
-static struct device_attribute w1_slave_attribute =
- __ATTR(name, S_IRUGO, w1_default_read_name, NULL);
-
-static struct device_attribute w1_slave_attribute_val =
- __ATTR(value, S_IRUGO, w1_default_read_name, NULL);
-
-static struct bin_attribute w1_slave_bin_attribute = {
- .attr = {
- .name = "w1_slave",
- .mode = S_IRUGO,
- .owner = THIS_MODULE,
- },
- .size = W1_SLAVE_DATA_SIZE,
- .read = &w1_default_read_bin,
-};
-

static struct bus_type w1_bus_type = {
.name = "w1",
@@ -279,6 +245,72 @@ void w1_destroy_master_attributes(struct
sysfs_remove_group(&master->dev.kobj, &w1_master_defattr_group);
}

+static ssize_t w1_slave_attribute_show_family(struct device *dev, char *buf)
+{
+ struct w1_slave *slave = to_w1_slave(dev);
+
+ return sprintf(buf, "%02X\n", slave->reg_num.family);
+}
+
+static ssize_t w1_slave_attribute_show_serial(struct device *dev, char *buf)
+{
+ struct w1_slave *slave = to_w1_slave(dev);
+
+ return sprintf(buf, "%llX\n", (unsigned long long)slave->reg_num.id);
+}
+
+#define W1_SLAVE_ATTR_RO(_name, _mode) \
+ struct device_attribute w1_slave_attribute_##_name = \
+ __ATTR(_name, _mode, \
+ w1_slave_attribute_show_##_name, NULL)
+
+static W1_SLAVE_ATTR_RO(family, S_IRUGO);
+static W1_SLAVE_ATTR_RO(serial, S_IRUGO);
+
+static struct attribute *w1_slave_default_attrs[] = {
+ &w1_slave_attribute_family.attr,
+ &w1_slave_attribute_serial.attr,
+ NULL
+};
+
+static struct attribute_group w1_slave_defattr_group = {
+ .attrs = w1_slave_default_attrs,
+};
+
+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");
+}
+
+static struct device_attribute w1_slave_attribute =
+ __ATTR(name, S_IRUGO, w1_default_read_name, NULL);
+
+static struct device_attribute w1_slave_attribute_val =
+ __ATTR(value, S_IRUGO, w1_default_read_name, NULL);
+
+static struct bin_attribute w1_slave_bin_attribute = {
+ .attr = {
+ .name = "w1_slave",
+ .mode = S_IRUGO,
+ .owner = THIS_MODULE,
+ },
+ .size = W1_SLAVE_DATA_SIZE,
+ .read = &w1_default_read_bin,
+};
+
+static void w1_slave_release(struct device *dev)
+{
+ struct w1_slave *sl = container_of(dev, struct w1_slave, dev);
+
+ complete(&sl->dev_released);
+}
+
static int __w1_attach_slave_device(struct w1_slave *sl)
{
int err;
@@ -347,6 +379,18 @@ static int __w1_attach_slave_device(stru
return err;
}

+ err = sysfs_create_group(&sl->dev.kobj, &w1_slave_defattr_group);
+ if (err < 0) {
+ dev_err(&sl->dev,
+ "sysfs group creation for [%s] failed. err=%d\n",
+ sl->dev.bus_id, err);
+ sysfs_remove_bin_file(&sl->dev.kobj, &sl->attr_bin);
+ device_remove_file(&sl->dev, &sl->attr_name);
+ device_remove_file(&sl->dev, &sl->attr_val);
+ device_unregister(&sl->dev);
+ return err;
+ }
+
list_add_tail(&sl->w1_slave_entry, &sl->master->slist);

return 0;
@@ -426,7 +470,8 @@ static void w1_slave_detach(struct w1_sl
flush_signals(current);
}

- sysfs_remove_bin_file (&sl->dev.kobj, &sl->attr_bin);
+ sysfs_remove_group(&sl->dev.kobj, &w1_slave_defattr_group);
+ sysfs_remove_bin_file(&sl->dev.kobj, &sl->attr_bin);
device_remove_file(&sl->dev, &sl->attr_name);
device_remove_file(&sl->dev, &sl->attr_val);
device_unregister(&sl->dev);
Index: dtor/drivers/w1/w1.h
===================================================================
--- dtor.orig/drivers/w1/w1.h
+++ dtor/drivers/w1/w1.h
@@ -81,6 +81,7 @@ struct w1_slave
struct bin_attribute attr_bin;
struct device_attribute attr_name, attr_val;
};
+#define to_w1_slave(dev) container_of((dev), struct w1_slave, dev)

typedef void (* w1_slave_found_callback)(unsigned long, u64);

2005-04-21 07:46:54

by Dmitry Torokhov

[permalink] [raw]
Subject: [RFC/PATCH 6/22] W1: drop owner field from master and slave structures

W1: drop owner field from w1_master and w1_slave structures.
Just having it there does not magically fixes lifetime
rules.

Signed-off-by: Dmitry Torokhov <[email protected]>
---

w1.c | 1 -
w1.h | 2 --
w1_int.c | 1 -
3 files changed, 4 deletions(-)

Index: dtor/drivers/w1/w1_int.c
===================================================================
--- dtor.orig/drivers/w1/w1_int.c
+++ dtor/drivers/w1/w1_int.c
@@ -60,7 +60,6 @@ struct w1_master * w1_alloc_dev(u32 id,

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;
Index: dtor/drivers/w1/w1.c
===================================================================
--- dtor.orig/drivers/w1/w1.c
+++ dtor/drivers/w1/w1.c
@@ -407,7 +407,6 @@ static int w1_attach_slave_device(struct

memset(sl, 0, sizeof(*sl));

- sl->owner = THIS_MODULE;
sl->master = dev;
set_bit(W1_SLAVE_ACTIVE, &sl->flags);

Index: dtor/drivers/w1/w1.h
===================================================================
--- dtor.orig/drivers/w1/w1.h
+++ dtor/drivers/w1/w1.h
@@ -64,7 +64,6 @@ struct w1_reg_num

struct w1_slave
{
- struct module *owner;
unsigned char name[W1_MAXNAMELEN];
struct list_head node;
struct w1_reg_num reg_num;
@@ -108,7 +107,6 @@ struct w1_bus_master
struct w1_master
{
struct list_head node;
- struct module *owner;
unsigned char name[W1_MAXNAMELEN];
struct list_head slist;
int max_slave_count, slave_count;

2005-04-21 07:46:54

by Dmitry Torokhov

[permalink] [raw]
Subject: [RFC/PATCH 5/22] W1: list handling cleanup

W1: list handling cleanup. Most of the list_for_each_safe users
don't need *_safe variant, *_entry variant is better suited
in most places. Also, checking retrieved list element for
null is a bit pointless...

Signed-off-by: Dmitry Torokhov <[email protected]>
---

w1.c | 131 +++++++++++++++++++++++----------------------------------------
w1.h | 6 +-
w1_int.c | 23 +++--------
3 files changed, 58 insertions(+), 102 deletions(-)

Index: dtor/drivers/w1/w1.c
===================================================================
--- dtor.orig/drivers/w1/w1.c
+++ dtor/drivers/w1/w1.c
@@ -184,6 +184,7 @@ static ssize_t w1_master_attribute_show_

{
struct w1_master *md = container_of(dev, struct w1_master, dev);
+ struct w1_slave *slave;
int c = PAGE_SIZE;

if (down_interruptible(&md->mutex))
@@ -191,16 +192,9 @@ static ssize_t w1_master_attribute_show_

if (md->slave_count == 0)
c -= snprintf(buf + PAGE_SIZE - c, c, "not found.\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\n", sl->name);
- }
- }
+ else
+ list_for_each_entry(slave, &md->slist, node)
+ c -= snprintf(buf + PAGE_SIZE - c, c, "%s\n", slave->name);

up(&md->mutex);

@@ -391,7 +385,7 @@ static int __w1_attach_slave_device(stru
return err;
}

- list_add_tail(&sl->w1_slave_entry, &sl->master->slist);
+ list_add_tail(&sl->node, &sl->master->slist);

return 0;
}
@@ -415,7 +409,7 @@ static int w1_attach_slave_device(struct

sl->owner = THIS_MODULE;
sl->master = dev;
- set_bit(W1_SLAVE_ACTIVE, (long *)&sl->flags);
+ set_bit(W1_SLAVE_ACTIVE, &sl->flags);

memcpy(&sl->reg_num, rn, sizeof(sl->reg_num));
atomic_set(&sl->refcnt, 0);
@@ -484,29 +478,27 @@ static void w1_slave_detach(struct w1_sl

static struct w1_master *w1_search_master(unsigned long data)
{
- struct w1_master *dev;
+ struct w1_master *master;
int found = 0;

spin_lock_irq(&w1_mlock);
- list_for_each_entry(dev, &w1_masters, w1_master_entry) {
- if (dev->bus_master->data == data) {
+ list_for_each_entry(master, &w1_masters, node) {
+ if (master->bus_master->data == data) {
found = 1;
- atomic_inc(&dev->refcnt);
+ atomic_inc(&master->refcnt);
break;
}
}
spin_unlock_irq(&w1_mlock);

- return (found)?dev:NULL;
+ return found ? master : NULL;
}

void w1_slave_found(unsigned long data, u64 rn)
{
int slave_count;
- struct w1_slave *sl;
- struct list_head *ent;
+ struct w1_slave *slave;
struct w1_reg_num *tmp;
- int family_found = 0;
struct w1_master *dev;

dev = w1_search_master(data);
@@ -519,20 +511,14 @@ void w1_slave_found(unsigned long data,
tmp = (struct w1_reg_num *) &rn;

slave_count = 0;
- list_for_each(ent, &dev->slist) {
+ list_for_each_entry(slave, &dev->slist, node) {

- 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) {
- set_bit(W1_SLAVE_ACTIVE, (long *)&sl->flags);
- break;
- } else if (sl->reg_num.family == tmp->family) {
- family_found = 1;
+ if (slave->reg_num.family == tmp->family &&
+ slave->reg_num.id == tmp->id &&
+ slave->reg_num.crc == tmp->crc) {
+ set_bit(W1_SLAVE_ACTIVE, &slave->flags);
break;
}
-
slave_count++;
}

@@ -635,9 +621,8 @@ void w1_search(struct w1_master *dev)

int w1_control(void *data)
{
- struct w1_slave *sl;
- struct w1_master *dev;
- struct list_head *ent, *ment, *n, *mn;
+ struct w1_slave *slave, *nexts;
+ struct w1_master *master, *nextm;
int err, have_to_wait = 0;

daemonize("w1_control");
@@ -652,52 +637,42 @@ int w1_control(void *data)
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);
+ list_for_each_entry_safe(master, nextm, &w1_masters, node) {

- if (!control_needs_exit && !dev->need_exit)
+ if (!control_needs_exit && !master->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) {
+ if (!master->initialized) {
have_to_wait = 1;
continue;
}

spin_lock(&w1_mlock);
- list_del(&dev->w1_master_entry);
+ list_del(&master->node);
spin_unlock(&w1_mlock);

if (control_needs_exit) {
- dev->need_exit = 1;
+ master->need_exit = 1;

- err = kill_proc(dev->kpid, SIGTERM, 1);
+ err = kill_proc(master->kpid, SIGTERM, 1);
if (err)
- dev_err(&dev->dev,
+ dev_err(&master->dev,
"Failed to send signal to w1 kernel thread %d.\n",
- dev->kpid);
+ master->kpid);
}

- wait_for_completion(&dev->dev_exited);
+ wait_for_completion(&master->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);
- }
+ list_for_each_entry_safe(slave, nexts, &master->slist, node) {
+ list_del(&slave->node);
+ w1_slave_detach(slave);
+ kfree(slave);
}
- w1_destroy_master_attributes(dev);
- atomic_dec(&dev->refcnt);
+ w1_destroy_master_attributes(master);
+ atomic_dec(&master->refcnt);
}
}

@@ -707,8 +682,7 @@ int w1_control(void *data)
int w1_process(void *data)
{
struct w1_master *dev = (struct w1_master *) data;
- struct list_head *ent, *n;
- struct w1_slave *sl;
+ struct w1_slave *slave, *next;

daemonize("%s", dev->name);
allow_signal(SIGTERM);
@@ -729,27 +703,21 @@ int w1_process(void *data)
if (down_interruptible(&dev->mutex))
continue;

- list_for_each_safe(ent, n, &dev->slist) {
- sl = list_entry(ent, struct w1_slave, w1_slave_entry);
-
- if (sl)
- clear_bit(W1_SLAVE_ACTIVE, (long *)&sl->flags);
- }
+ list_for_each_entry(slave, &dev->slist, node)
+ clear_bit(W1_SLAVE_ACTIVE, &slave->flags);

w1_search_devices(dev, w1_slave_found);

- list_for_each_safe(ent, n, &dev->slist) {
- sl = list_entry(ent, struct w1_slave, w1_slave_entry);
-
- if (sl && !test_bit(W1_SLAVE_ACTIVE, (unsigned long *)&sl->flags) && !--sl->ttl) {
- list_del (&sl->w1_slave_entry);
-
- w1_slave_detach (sl);
- kfree (sl);
+ list_for_each_entry_safe(slave, next, &dev->slist, node) {

+ if (test_bit(W1_SLAVE_ACTIVE, &slave->flags))
+ slave->ttl = dev->slave_ttl;
+ else if (!--slave->ttl) {
+ list_del(&slave->node);
+ w1_slave_detach(slave);
+ kfree(slave);
dev->slave_count--;
- } else if (test_bit(W1_SLAVE_ACTIVE, (unsigned long *)&sl->flags))
- sl->ttl = dev->slave_ttl;
+ }
}
up(&dev->mutex);
}
@@ -802,13 +770,10 @@ err_out_exit_init:

void w1_fini(void)
{
- struct w1_master *dev;
- struct list_head *ent, *n;
+ struct w1_master *master, *next;

- list_for_each_safe(ent, n, &w1_masters) {
- dev = list_entry(ent, struct w1_master, w1_master_entry);
- __w1_remove_master_device(dev);
- }
+ list_for_each_entry_safe(master, next, &w1_masters, node)
+ __w1_remove_master_device(master);

control_needs_exit = 1;

Index: dtor/drivers/w1/w1.h
===================================================================
--- dtor.orig/drivers/w1/w1.h
+++ dtor/drivers/w1/w1.h
@@ -66,11 +66,11 @@ struct w1_slave
{
struct module *owner;
unsigned char name[W1_MAXNAMELEN];
- struct list_head w1_slave_entry;
+ struct list_head node;
struct w1_reg_num reg_num;
atomic_t refcnt;
u8 rom[9];
- u32 flags;
+ unsigned long flags;
int ttl;

struct w1_master *master;
@@ -107,7 +107,7 @@ struct w1_bus_master

struct w1_master
{
- struct list_head w1_master_entry;
+ struct list_head node;
struct module *owner;
unsigned char name[W1_MAXNAMELEN];
struct list_head slist;
Index: dtor/drivers/w1/w1_int.c
===================================================================
--- dtor.orig/drivers/w1/w1_int.c
+++ dtor/drivers/w1/w1_int.c
@@ -142,7 +142,7 @@ int w1_add_master_device(struct w1_bus_m
dev->initialized = 1;

spin_lock(&w1_mlock);
- list_add(&dev->w1_master_entry, &w1_masters);
+ list_add(&dev->node, &w1_masters);
spin_unlock(&w1_mlock);

msg.id.mst.id = dev->id;
@@ -196,24 +196,15 @@ void __w1_remove_master_device(struct w1

void w1_remove_master_device(struct w1_bus_master *bm)
{
- struct w1_master *dev = NULL;
- struct list_head *ent, *n;
+ struct w1_master *dev;

- 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)
+ list_for_each_entry(dev, &w1_masters, node)
+ if (dev->initialized && dev->bus_master->data == bm->data) {
+ __w1_remove_master_device(dev);
break;
- }
-
- if (!dev) {
- printk(KERN_ERR "Device doesn't exist.\n");
- return;
- }
+ }

- __w1_remove_master_device(dev);
+ printk(KERN_ERR "Device doesn't exist.\n");
}

EXPORT_SYMBOL(w1_add_master_device);

2005-04-21 07:52:24

by Dmitry Torokhov

[permalink] [raw]
Subject: [RFC/PATCH 7/22] W1: bus operations cleanup

W1: cleanup bus operations code:
- have bus operatiions accept w1_master instead of unsigned long
and drop data field from w1_bus_master so the structure can be
statically allocated by driver implementing it;
- rename w1_bus_master to w1_bus_ops to avoid confusion with
w1_master;
- separate master registering and allocation so drivers can set
up proper link between private data and master and set useable
master's name.

Signed-off-by: Dmitry Torokhov <[email protected]>
---

ds_w1_bridge.c | 87 ++++++++++++++++++++++++++++---------------------------
matrox_w1.c | 64 +++++++++++++++++++++-------------------
w1.c | 36 +++--------------------
w1.h | 30 ++++++++-----------
w1_int.c | 89 +++++++++++++++++++--------------------------------------
w1_int.h | 8 ++---
w1_io.c | 54 ++++++++++++++++++----------------
7 files changed, 160 insertions(+), 208 deletions(-)

Index: dtor/drivers/w1/ds_w1_bridge.c
===================================================================
--- dtor.orig/drivers/w1/ds_w1_bridge.c
+++ dtor/drivers/w1/ds_w1_bridge.c
@@ -27,12 +27,12 @@
#include "dscore.h"

static struct ds_device *ds_dev;
-static struct w1_bus_master *ds_bus_master;
+static struct w1_master *ds_master;

-static u8 ds9490r_touch_bit(unsigned long data, u8 bit)
+static u8 ds9490r_touch_bit(struct w1_master *master, u8 bit)
{
+ struct ds_device *dev = master->private;
u8 ret;
- struct ds_device *dev = (struct ds_device *)data;

if (ds_touch_bit(dev, bit, &ret))
return 0;
@@ -40,23 +40,23 @@ static u8 ds9490r_touch_bit(unsigned lon
return ret;
}

-static void ds9490r_write_bit(unsigned long data, u8 bit)
+static void ds9490r_write_bit(struct w1_master *master, u8 bit)
{
- struct ds_device *dev = (struct ds_device *)data;
+ struct ds_device *dev = master->private;

ds_write_bit(dev, bit);
}

-static void ds9490r_write_byte(unsigned long data, u8 byte)
+static void ds9490r_write_byte(struct w1_master *master, u8 byte)
{
- struct ds_device *dev = (struct ds_device *)data;
+ struct ds_device *dev = master->private;

ds_write_byte(dev, byte);
}

-static u8 ds9490r_read_bit(unsigned long data)
+static u8 ds9490r_read_bit(struct w1_master *master)
{
- struct ds_device *dev = (struct ds_device *)data;
+ struct ds_device *dev = master->private;
int err;
u8 bit = 0;

@@ -70,9 +70,9 @@ static u8 ds9490r_read_bit(unsigned long
return bit & 1;
}

-static u8 ds9490r_read_byte(unsigned long data)
+static u8 ds9490r_read_byte(struct w1_master *master)
{
- struct ds_device *dev = (struct ds_device *)data;
+ struct ds_device *dev = master->private;
int err;
u8 byte = 0;

@@ -83,16 +83,16 @@ static u8 ds9490r_read_byte(unsigned lon
return byte;
}

-static void ds9490r_write_block(unsigned long data, u8 *buf, int len)
+static void ds9490r_write_block(struct w1_master *master, u8 *buf, int len)
{
- struct ds_device *dev = (struct ds_device *)data;
+ struct ds_device *dev = master->private;

ds_write_block(dev, buf, len);
}

-static u8 ds9490r_read_block(unsigned long data, u8 *buf, int len)
+static u8 ds9490r_read_block(struct w1_master *master, u8 *buf, int len)
{
- struct ds_device *dev = (struct ds_device *)data;
+ struct ds_device *dev = master->private;
int err;

err = ds_read_block(dev, buf, len);
@@ -102,9 +102,9 @@ static u8 ds9490r_read_block(unsigned lo
return len;
}

-static u8 ds9490r_reset(unsigned long data)
+static u8 ds9490r_reset(struct w1_master *master)
{
- struct ds_device *dev = (struct ds_device *)data;
+ struct ds_device *dev = master->private;
struct ds_status st;
int err;

@@ -112,59 +112,60 @@ static u8 ds9490r_reset(unsigned long da

err = ds_reset(dev, &st);
if (err)
- return 1;
+ return -1;

return 0;
}

+static struct w1_bus_ops ds_bus_ops = {
+ .touch_bit = ds9490r_touch_bit,
+ .read_bit = ds9490r_read_bit,
+ .write_bit = ds9490r_write_bit,
+ .read_byte = ds9490r_read_byte,
+ .write_byte = ds9490r_write_byte,
+ .read_block = ds9490r_read_block,
+ .write_block = ds9490r_write_block,
+ .reset_bus = ds9490r_reset,
+};
+
static int __devinit ds_w1_init(void)
{
int err;

- ds_bus_master = kmalloc(sizeof(*ds_bus_master), GFP_KERNEL);
- if (!ds_bus_master) {
- printk(KERN_ERR "Failed to allocate DS9490R USB<->W1 bus_master structure.\n");
- return -ENOMEM;
- }
-
ds_dev = ds_get_device();
if (!ds_dev) {
printk(KERN_ERR "DS9490R is not registered.\n");
- err = -ENODEV;
- goto err_out_free_bus_master;
+ return -ENODEV;
}

- memset(ds_bus_master, 0, sizeof(*ds_bus_master));
+ ds_master = w1_allocate_master_device();
+ if (!ds_master) {
+ err = -ENOMEM;
+ goto err_out;
+ }

- ds_bus_master->data = (unsigned long)ds_dev;
- ds_bus_master->touch_bit = &ds9490r_touch_bit;
- ds_bus_master->read_bit = &ds9490r_read_bit;
- ds_bus_master->write_bit = &ds9490r_write_bit;
- ds_bus_master->read_byte = &ds9490r_read_byte;
- ds_bus_master->write_byte = &ds9490r_write_byte;
- ds_bus_master->read_block = &ds9490r_read_block;
- ds_bus_master->write_block = &ds9490r_write_block;
- ds_bus_master->reset_bus = &ds9490r_reset;
+ strlcpy(ds_master->name, "DS <-> 1-Wire Bridge",
+ sizeof(ds_master->name));
+ ds_master->bus_ops = &ds_bus_ops;
+ ds_master->private = ds_dev;

- err = w1_add_master_device(ds_bus_master);
+ err = w1_add_master_device(ds_master);
if (err)
- goto err_out_put_device;
+ goto err_out;

return 0;

-err_out_put_device:
+err_out:
+ kfree(ds_master);
ds_put_device(ds_dev);
-err_out_free_bus_master:
- kfree(ds_bus_master);

return err;
}

static void __devexit ds_w1_fini(void)
{
- w1_remove_master_device(ds_bus_master);
+ w1_remove_master_device(ds_master);
ds_put_device(ds_dev);
- kfree(ds_bus_master);
}

module_init(ds_w1_init);
Index: dtor/drivers/w1/w1_int.c
===================================================================
--- dtor.orig/drivers/w1/w1_int.c
+++ dtor/drivers/w1/w1_int.c
@@ -39,16 +39,14 @@ extern spinlock_t w1_mlock;

extern int w1_process(void *);

-struct w1_master * w1_alloc_dev(u32 id, int slave_count, int slave_ttl,
- struct device_driver *driver, struct device *device)
+struct w1_master *w1_allocate_master_device(void)
{
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);
+ dev = kcalloc(1, sizeof(struct w1_master), GFP_KERNEL);
if (!dev) {
printk(KERN_ERR
"Failed to allocate %zd bytes for new w1 device.\n",
@@ -56,17 +54,10 @@ struct w1_master * w1_alloc_dev(u32 id,
return NULL;
}

- memset(dev, 0, sizeof(struct w1_master) + sizeof(struct w1_bus_master));
-
- dev->bus_master = (struct w1_bus_master *)(dev + 1);
-
- dev->max_slave_count = slave_count;
- dev->slave_count = 0;
- dev->attempts = 0;
+ dev->max_slave_count = w1_max_slave_count;
dev->kpid = -1;
- dev->initialized = 0;
- dev->id = id;
- dev->slave_ttl = slave_ttl;
+ dev->id = w1_ids++;
+ dev->slave_ttl = w1_max_slave_ttl;

atomic_set(&dev->refcnt, 2);

@@ -76,30 +67,14 @@ struct w1_master * w1_alloc_dev(u32 id,
init_completion(&dev->dev_released);
init_completion(&dev->dev_exited);

- memcpy(&dev->dev, device, sizeof(struct device));
+ dev->dev = w1_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->driver = &w1_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) for w1 master %s.\n",
- NETLINK_NFLOG, dev->dev.bus_id);
- }
-
- err = device_register(&dev->dev);
- if (err) {
- printk(KERN_ERR "Failed to register master device. err=%d\n", err);
- if (dev->nls && dev->nls->sk_socket)
- sock_release(dev->nls->sk_socket);
- memset(dev, 0, sizeof(struct w1_master));
- kfree(dev);
- dev = NULL;
- }

return dev;
}
@@ -109,35 +84,43 @@ void w1_free_dev(struct w1_master *dev)
device_unregister(&dev->dev);
if (dev->nls && dev->nls->sk_socket)
sock_release(dev->nls->sk_socket);
- memset(dev, 0, sizeof(struct w1_master) + sizeof(struct w1_bus_master));
+ memset(dev, 0, sizeof(struct w1_master));
kfree(dev);
}

-int w1_add_master_device(struct w1_bus_master *master)
+int w1_add_master_device(struct w1_master *dev)
{
- struct w1_master *dev;
- int retval = 0;
+ int error;
struct w1_netlink_msg msg;

- dev = w1_alloc_dev(w1_ids++, w1_max_slave_count, w1_max_slave_ttl, &w1_driver, &w1_device);
- if (!dev)
- return -ENOMEM;
+ dev->nls = netlink_kernel_create(NETLINK_NFLOG, NULL);
+ if (!dev->nls) {
+ printk(KERN_ERR "Failed to create new netlink socket(%u) for w1 master %s.\n",
+ NETLINK_NFLOG, dev->dev.bus_id);
+ return -1;
+ }
+
+ error = device_register(&dev->dev);
+ if (error) {
+ printk(KERN_ERR "Failed to register master device. err=%d\n", error);
+ if (dev->nls && dev->nls->sk_socket)
+ sock_release(dev->nls->sk_socket);
+ return error;
+ }

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;
+ error = dev->kpid;
goto err_out_free_dev;
}

- retval = w1_create_master_attributes(dev);
- if (retval)
+ error = w1_create_master_attributes(dev);
+ if (error)
goto err_out_kill_thread;

- memcpy(dev->bus_master, master, sizeof(struct w1_bus_master));
-
dev->initialized = 1;

spin_lock(&w1_mlock);
@@ -162,10 +145,10 @@ err_out_kill_thread:
err_out_free_dev:
w1_free_dev(dev);

- return retval;
+ return error;
}

-void __w1_remove_master_device(struct w1_master *dev)
+void w1_remove_master_device(struct w1_master *dev)
{
int err;
struct w1_netlink_msg msg;
@@ -193,18 +176,6 @@ void __w1_remove_master_device(struct w1
w1_free_dev(dev);
}

-void w1_remove_master_device(struct w1_bus_master *bm)
-{
- struct w1_master *dev;
-
- list_for_each_entry(dev, &w1_masters, node)
- if (dev->initialized && dev->bus_master->data == bm->data) {
- __w1_remove_master_device(dev);
- break;
- }
-
- printk(KERN_ERR "Device doesn't exist.\n");
-}
-
+EXPORT_SYMBOL(w1_allocate_master_device);
EXPORT_SYMBOL(w1_add_master_device);
EXPORT_SYMBOL(w1_remove_master_device);
Index: dtor/drivers/w1/matrox_w1.c
===================================================================
--- dtor.orig/drivers/w1/matrox_w1.c
+++ dtor/drivers/w1/matrox_w1.c
@@ -85,14 +85,10 @@ struct matrox_device

unsigned long phys_addr;
void __iomem *virt_addr;
- unsigned long found;

- struct w1_bus_master *bus_master;
+ struct w1_master *master;
};

-static u8 matrox_w1_read_ddc_bit(unsigned long);
-static void matrox_w1_write_ddc_bit(unsigned long, u8);
-
/*
* These functions read and write DDC Data bit.
*
@@ -122,10 +118,10 @@ static __inline__ void matrox_w1_write_r
wmb();
}

-static void matrox_w1_write_ddc_bit(unsigned long data, u8 bit)
+static void matrox_w1_write_ddc_bit(struct w1_master *master, u8 bit)
{
+ struct matrox_device *dev = master->private;
u8 ret;
- struct matrox_device *dev = (struct matrox_device *) data;

if (bit)
bit = 0;
@@ -137,16 +133,18 @@ static void matrox_w1_write_ddc_bit(unsi
matrox_w1_write_reg(dev, MATROX_GET_DATA, 0x00);
}

-static u8 matrox_w1_read_ddc_bit(unsigned long data)
+static u8 matrox_w1_read_ddc_bit(struct w1_master *master)
{
- u8 ret;
- struct matrox_device *dev = (struct matrox_device *) data;
-
- ret = matrox_w1_read_reg(dev, MATROX_GET_DATA);
+ struct matrox_device *dev = master->private;

- return ret;
+ return matrox_w1_read_reg(dev, MATROX_GET_DATA);
}

+static struct w1_bus_ops matrox_bus_ops = {
+ .read_bit = matrox_w1_read_ddc_bit,
+ .write_bit = matrox_w1_write_ddc_bit,
+};
+
static void matrox_w1_hw_init(struct matrox_device *dev)
{
matrox_w1_write_reg(dev, MATROX_GET_DATA, 0xFF);
@@ -156,6 +154,7 @@ static void matrox_w1_hw_init(struct mat
static int __devinit matrox_w1_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
struct matrox_device *dev;
+ struct w1_master *master;
int err;

assert(pdev != NULL);
@@ -164,8 +163,7 @@ static int __devinit matrox_w1_probe(str
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);
+ dev = kcalloc(1, sizeof(struct matrox_device), GFP_KERNEL);
if (!dev) {
dev_err(&pdev->dev,
"%s: Failed to create new matrox_device object.\n",
@@ -173,10 +171,6 @@ static int __devinit matrox_w1_probe(str
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
*/
@@ -196,24 +190,34 @@ static int __devinit matrox_w1_probe(str
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;
+ dev->master = master = w1_allocate_master_device();
+ if (!master) {
+ err = -ENOMEM;
+ goto err_out_free_device;
+ }
+
+ strlcpy(master->name, "Matrox <-> 1-Wire Bridge",
+ sizeof(master->name));
+ master->bus_ops = &matrox_bus_ops;
+ master->private = dev;
+ master->dev.parent = &pdev->dev;
+
+ matrox_w1_hw_init(dev);

- err = w1_add_master_device(dev->bus_master);
+ err = w1_add_master_device(master);
if (err)
- goto err_out_free_device;
+ goto err_out_free_master;

pci_set_drvdata(pdev, dev);

- dev->found = 1;
-
dev_info(&pdev->dev, "Matrox G400 GPIO transport layer for 1-wire.\n");

return 0;

+err_out_free_master:
+ kfree(master);
+
err_out_free_device:
kfree(dev);

@@ -226,10 +230,8 @@ static void __devexit matrox_w1_remove(s

assert(dev != NULL);

- if (dev->found) {
- w1_remove_master_device(dev->bus_master);
- iounmap(dev->virt_addr);
- }
+ w1_remove_master_device(dev->master);
+ iounmap(dev->virt_addr);
kfree(dev);
}

Index: dtor/drivers/w1/w1.c
===================================================================
--- dtor.orig/drivers/w1/w1.c
+++ dtor/drivers/w1/w1.c
@@ -125,7 +125,7 @@ static ssize_t w1_master_attribute_show_
if (down_interruptible(&md->mutex))
return -EBUSY;

- count = sprintf(buf, "0x%p\n", md->bus_master);
+ count = sprintf(buf, "0x%p\n", md->private);

up(&md->mutex);
return count;
@@ -475,37 +475,13 @@ static void w1_slave_detach(struct w1_sl
w1_netlink_send(sl->master, &msg);
}

-static struct w1_master *w1_search_master(unsigned long data)
-{
- struct w1_master *master;
- int found = 0;
-
- spin_lock_irq(&w1_mlock);
- list_for_each_entry(master, &w1_masters, node) {
- if (master->bus_master->data == data) {
- found = 1;
- atomic_inc(&master->refcnt);
- break;
- }
- }
- spin_unlock_irq(&w1_mlock);
-
- return found ? master : NULL;
-}
-
-void w1_slave_found(unsigned long data, u64 rn)
+void w1_slave_found(struct w1_master *dev, u64 rn)
{
int slave_count;
struct w1_slave *slave;
struct w1_reg_num *tmp;
- struct w1_master *dev;

- dev = w1_search_master(data);
- if (!dev) {
- printk(KERN_ERR "Failed to find w1 master device for data %08lx, it is impossible.\n",
- data);
- return;
- }
+ atomic_inc(&dev->refcnt);

tmp = (struct w1_reg_num *) &rn;

@@ -600,7 +576,7 @@ void w1_search(struct w1_master *dev)
* and make all who don't have "search_bit" in "i"'th position
* in it's registration number sleep.
*/
- if (dev->bus_master->touch_bit)
+ if (dev->bus_ops->touch_bit)
w1_touch_bit(dev, search_bit);
else
w1_write_bit(dev, search_bit);
@@ -613,7 +589,7 @@ void w1_search(struct w1_master *dev)

desc_bit = last_zero;

- w1_slave_found(dev->bus_master->data, rn);
+ w1_slave_found(dev, rn);
}
}

@@ -772,7 +748,7 @@ void w1_fini(void)
struct w1_master *master, *next;

list_for_each_entry_safe(master, next, &w1_masters, node)
- __w1_remove_master_device(master);
+ w1_remove_master_device(master);

control_needs_exit = 1;

Index: dtor/drivers/w1/w1_io.c
===================================================================
--- dtor.orig/drivers/w1/w1_io.c
+++ dtor/drivers/w1/w1_io.c
@@ -13,7 +13,7 @@
* 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.
- *
+ ate*
* 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
@@ -57,23 +57,25 @@ void w1_delay(unsigned long tm)

u8 w1_touch_bit(struct w1_master *dev, int bit)
{
- if (dev->bus_master->touch_bit)
- return dev->bus_master->touch_bit(dev->bus_master->data, bit);
+ if (dev->bus_ops->touch_bit)
+ return dev->bus_ops->touch_bit(dev, bit);
else
return w1_read_bit(dev);
}

void w1_write_bit(struct w1_master *dev, int bit)
{
+ struct w1_bus_ops *bus_ops = dev->bus_ops;
+
if (bit) {
- dev->bus_master->write_bit(dev->bus_master->data, 0);
+ bus_ops->write_bit(dev, 0);
w1_delay(6);
- dev->bus_master->write_bit(dev->bus_master->data, 1);
+ bus_ops->write_bit(dev, 1);
w1_delay(64);
} else {
- dev->bus_master->write_bit(dev->bus_master->data, 0);
+ bus_ops->write_bit(dev, 0);
w1_delay(60);
- dev->bus_master->write_bit(dev->bus_master->data, 1);
+ bus_ops->write_bit(dev, 1);
w1_delay(10);
}
}
@@ -82,8 +84,8 @@ void w1_write_8(struct w1_master *dev, u
{
int i;

- if (dev->bus_master->write_byte)
- dev->bus_master->write_byte(dev->bus_master->data, byte);
+ if (dev->bus_ops->write_byte)
+ dev->bus_ops->write_byte(dev, byte);
else
for (i = 0; i < 8; ++i)
w1_write_bit(dev, (byte >> i) & 0x1);
@@ -91,14 +93,15 @@ void w1_write_8(struct w1_master *dev, u

u8 w1_read_bit(struct w1_master *dev)
{
+ struct w1_bus_ops *bus_ops = dev->bus_ops;
int result;

- dev->bus_master->write_bit(dev->bus_master->data, 0);
+ bus_ops->write_bit(dev, 0);
w1_delay(6);
- dev->bus_master->write_bit(dev->bus_master->data, 1);
+ bus_ops->write_bit(dev, 1);
w1_delay(9);

- result = dev->bus_master->read_bit(dev->bus_master->data);
+ result = bus_ops->read_bit(dev);
w1_delay(55);

return result & 0x1;
@@ -109,8 +112,8 @@ u8 w1_read_8(struct w1_master * dev)
int i;
u8 res = 0;

- if (dev->bus_master->read_byte)
- res = dev->bus_master->read_byte(dev->bus_master->data);
+ if (dev->bus_ops->read_byte)
+ res = dev->bus_ops->read_byte(dev);
else
for (i = 0; i < 8; ++i)
res |= (w1_read_bit(dev) << i);
@@ -122,8 +125,8 @@ void w1_write_block(struct w1_master *de
{
int i;

- if (dev->bus_master->write_block)
- dev->bus_master->write_block(dev->bus_master->data, buf, len);
+ if (dev->bus_ops->write_block)
+ dev->bus_ops->write_block(dev, buf, len);
else
for (i = 0; i < len; ++i)
w1_write_8(dev, buf[i]);
@@ -134,8 +137,8 @@ u8 w1_read_block(struct w1_master *dev,
int i;
u8 ret;

- if (dev->bus_master->read_block)
- ret = dev->bus_master->read_block(dev->bus_master->data, buf, len);
+ if (dev->bus_ops->read_block)
+ ret = dev->bus_ops->read_block(dev, buf, len);
else {
for (i = 0; i < len; ++i)
buf[i] = w1_read_8(dev);
@@ -147,17 +150,18 @@ u8 w1_read_block(struct w1_master *dev,

int w1_reset_bus(struct w1_master *dev)
{
+ struct w1_bus_ops *bus_ops = dev->bus_ops;
int result = 0;

- if (dev->bus_master->reset_bus)
- result = dev->bus_master->reset_bus(dev->bus_master->data) & 0x1;
+ if (bus_ops->reset_bus)
+ result = bus_ops->reset_bus(dev) & 0x1;
else {
- dev->bus_master->write_bit(dev->bus_master->data, 0);
+ bus_ops->write_bit(dev, 0);
w1_delay(480);
- dev->bus_master->write_bit(dev->bus_master->data, 1);
+ bus_ops->write_bit(dev, 1);
w1_delay(70);

- result = dev->bus_master->read_bit(dev->bus_master->data) & 0x1;
+ result = bus_ops->read_bit(dev) & 0x1;
w1_delay(410);
}

@@ -177,8 +181,8 @@ u8 w1_calc_crc8(u8 * data, int len)
void w1_search_devices(struct w1_master *dev, w1_slave_found_callback cb)
{
dev->attempts++;
- if (dev->bus_master->search)
- dev->bus_master->search(dev->bus_master->data, cb);
+ if (dev->bus_ops->search)
+ dev->bus_ops->search(dev, cb);
else
w1_search(dev);
}
Index: dtor/drivers/w1/w1_int.h
===================================================================
--- dtor.orig/drivers/w1/w1_int.h
+++ dtor/drivers/w1/w1_int.h
@@ -24,13 +24,13 @@

#include <linux/kernel.h>
#include <linux/device.h>
+#include <linux/err.h>

#include "w1.h"

-struct w1_master * w1_alloc_dev(u32, int, int, struct device_driver *, struct device *);
+struct w1_master *w1_allocate_master_device(void);
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 *);
+int w1_add_master_device(struct w1_master *);
+void w1_remove_master_device(struct w1_master *);

#endif /* __W1_INT_H */
Index: dtor/drivers/w1/w1.h
===================================================================
--- dtor.orig/drivers/w1/w1.h
+++ dtor/drivers/w1/w1.h
@@ -82,26 +82,25 @@ struct w1_slave
};
#define to_w1_slave(dev) container_of((dev), struct w1_slave, dev)

-typedef void (* w1_slave_found_callback)(unsigned long, u64);
+struct w1_master;
+typedef void (*w1_slave_found_callback)(struct w1_master *, u64);

-struct w1_bus_master
+struct w1_bus_ops
{
- unsigned long data;
+ u8 (*read_bit)(struct w1_master *);
+ void (*write_bit)(struct w1_master *, u8);

- u8 (*read_bit)(unsigned long);
- void (*write_bit)(unsigned long, u8);
+ u8 (*read_byte)(struct w1_master *);
+ void (*write_byte)(struct w1_master *, u8);

- u8 (*read_byte)(unsigned long);
- void (*write_byte)(unsigned long, u8);
+ u8 (*read_block)(struct w1_master *, u8 *, int);
+ void (*write_block)(struct w1_master *, u8 *, int);

- u8 (*read_block)(unsigned long, u8 *, int);
- void (*write_block)(unsigned long, u8 *, int);
+ u8 (*touch_bit)(struct w1_master *, u8);

- u8 (*touch_bit)(unsigned long, u8);
+ u8 (*reset_bus)(struct w1_master *);

- u8 (*reset_bus)(unsigned long);
-
- void (*search)(unsigned long, w1_slave_found_callback);
+ void (*search)(struct w1_master *, w1_slave_found_callback);
};

struct w1_master
@@ -117,8 +116,7 @@ struct w1_master

atomic_t refcnt;

- void *priv;
- int priv_size;
+ void *private;

int need_exit;
pid_t kpid;
@@ -129,7 +127,7 @@ struct w1_master
struct completion dev_released;
struct completion dev_exited;

- struct w1_bus_master *bus_master;
+ struct w1_bus_ops *bus_ops;

u32 seq, groups;
struct sock *nls;

2005-04-21 07:55:38

by Dmitry Torokhov

[permalink] [raw]
Subject: [RFC/PATCH 8/22] W1: merge master code into one file

W1: fold w1_int.c into w1.c - there is no point in artificially
separating code for master devices between 2 files.

Signed-off-by: Dmitry Torokhov <[email protected]>
---

drivers/w1/w1_int.c | 181 -----------------------------------------
drivers/w1/w1_int.h | 36 --------
dtor/drivers/w1/Makefile | 2
dtor/drivers/w1/ds_w1_bridge.c | 1
dtor/drivers/w1/matrox_w1.c | 1
dtor/drivers/w1/w1.c | 158 +++++++++++++++++++++++++++++++++--
dtor/drivers/w1/w1.h | 7 -
dtor/drivers/w1/w1_smem.c | 1
dtor/drivers/w1/w1_therm.c | 1
9 files changed, 155 insertions(+), 233 deletions(-)

Index: dtor/drivers/w1/ds_w1_bridge.c
===================================================================
--- dtor.orig/drivers/w1/ds_w1_bridge.c
+++ dtor/drivers/w1/ds_w1_bridge.c
@@ -23,7 +23,6 @@
#include <linux/types.h>

#include "../w1/w1.h"
-#include "../w1/w1_int.h"
#include "dscore.h"

static struct ds_device *ds_dev;
Index: dtor/drivers/w1/w1_therm.c
===================================================================
--- dtor.orig/drivers/w1/w1_therm.c
+++ dtor/drivers/w1/w1_therm.c
@@ -30,7 +30,6 @@

#include "w1.h"
#include "w1_io.h"
-#include "w1_int.h"
#include "w1_family.h"

MODULE_LICENSE("GPL");
Index: dtor/drivers/w1/w1_int.c
===================================================================
--- dtor.orig/drivers/w1/w1_int.c
+++ /dev/null
@@ -1,181 +0,0 @@
-/*
- * w1_int.c
- *
- * Copyright (c) 2004 Evgeniy Polyakov <[email protected]>
- *
- *
- * 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 <linux/delay.h>
-
-#include "w1.h"
-#include "w1_log.h"
-#include "w1_netlink.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 int w1_max_slave_count;
-extern int w1_max_slave_ttl;
-extern struct list_head w1_masters;
-extern spinlock_t w1_mlock;
-
-extern int w1_process(void *);
-
-struct w1_master *w1_allocate_master_device(void)
-{
- struct w1_master *dev;
-
- /*
- * We are in process context(kernel thread), so can sleep.
- */
- dev = kcalloc(1, sizeof(struct w1_master), GFP_KERNEL);
- if (!dev) {
- printk(KERN_ERR
- "Failed to allocate %zd bytes for new w1 device.\n",
- sizeof(struct w1_master));
- return NULL;
- }
-
- dev->max_slave_count = w1_max_slave_count;
- dev->kpid = -1;
- dev->id = w1_ids++;
- dev->slave_ttl = w1_max_slave_ttl;
-
- atomic_set(&dev->refcnt, 2);
-
- INIT_LIST_HEAD(&dev->slist);
- init_MUTEX(&dev->mutex);
-
- init_completion(&dev->dev_released);
- init_completion(&dev->dev_exited);
-
- dev->dev = w1_device;
- snprintf(dev->dev.bus_id, sizeof(dev->dev.bus_id),
- "w1_bus_master%u", dev->id);
-
- dev->driver = &w1_driver;
-
- dev->groups = 23;
- dev->seq = 1;
-
- return dev;
-}
-
-void w1_free_dev(struct w1_master *dev)
-{
- device_unregister(&dev->dev);
- if (dev->nls && dev->nls->sk_socket)
- sock_release(dev->nls->sk_socket);
- memset(dev, 0, sizeof(struct w1_master));
- kfree(dev);
-}
-
-int w1_add_master_device(struct w1_master *dev)
-{
- int error;
- struct w1_netlink_msg msg;
-
- dev->nls = netlink_kernel_create(NETLINK_NFLOG, NULL);
- if (!dev->nls) {
- printk(KERN_ERR "Failed to create new netlink socket(%u) for w1 master %s.\n",
- NETLINK_NFLOG, dev->dev.bus_id);
- return -1;
- }
-
- error = device_register(&dev->dev);
- if (error) {
- printk(KERN_ERR "Failed to register master device. err=%d\n", error);
- if (dev->nls && dev->nls->sk_socket)
- sock_release(dev->nls->sk_socket);
- return error;
- }
-
- 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);
- error = dev->kpid;
- goto err_out_free_dev;
- }
-
- error = w1_create_master_attributes(dev);
- if (error)
- goto err_out_kill_thread;
-
- dev->initialized = 1;
-
- spin_lock(&w1_mlock);
- list_add(&dev->node, &w1_masters);
- spin_unlock(&w1_mlock);
-
- msg.id.mst.id = dev->id;
- msg.id.mst.pid = dev->kpid;
- msg.type = W1_MASTER_ADD;
- w1_netlink_send(dev, &msg);
-
- 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 error;
-}
-
-void w1_remove_master_device(struct w1_master *dev)
-{
- int err;
- struct w1_netlink_msg msg;
-
- 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)) {
- printk(KERN_INFO "Waiting for %s to become free: refcnt=%d.\n",
- dev->name, atomic_read(&dev->refcnt));
-
- if (msleep_interruptible(1000))
- flush_signals(current);
- }
-
- msg.id.mst.id = dev->id;
- msg.id.mst.pid = dev->kpid;
- msg.type = W1_MASTER_REMOVE;
- w1_netlink_send(dev, &msg);
-
- w1_free_dev(dev);
-}
-
-EXPORT_SYMBOL(w1_allocate_master_device);
-EXPORT_SYMBOL(w1_add_master_device);
-EXPORT_SYMBOL(w1_remove_master_device);
Index: dtor/drivers/w1/Makefile
===================================================================
--- dtor.orig/drivers/w1/Makefile
+++ dtor/drivers/w1/Makefile
@@ -7,7 +7,7 @@ EXTRA_CFLAGS += -DNETLINK_DISABLED
endif

obj-$(CONFIG_W1) += wire.o
-wire-objs := w1.o w1_int.o w1_family.o w1_netlink.o w1_io.o
+wire-objs := w1.o w1_family.o w1_netlink.o w1_io.o

obj-$(CONFIG_W1_MATROX) += matrox_w1.o
obj-$(CONFIG_W1_THERM) += w1_therm.o
Index: dtor/drivers/w1/matrox_w1.c
===================================================================
--- dtor.orig/drivers/w1/matrox_w1.c
+++ dtor/drivers/w1/matrox_w1.c
@@ -36,7 +36,6 @@
#include <linux/timer.h>

#include "w1.h"
-#include "w1_int.h"
#include "w1_log.h"

MODULE_LICENSE("GPL");
Index: dtor/drivers/w1/w1.c
===================================================================
--- dtor.orig/drivers/w1/w1.c
+++ dtor/drivers/w1/w1.c
@@ -36,7 +36,6 @@
#include "w1.h"
#include "w1_io.h"
#include "w1_log.h"
-#include "w1_int.h"
#include "w1_family.h"
#include "w1_netlink.h"

@@ -45,15 +44,16 @@ MODULE_AUTHOR("Evgeniy Polyakov <johnpol
MODULE_DESCRIPTION("Driver for 1-wire Dallas network protocol.");

static int w1_timeout = 10;
-int w1_max_slave_count = 10;
-int w1_max_slave_ttl = 10;
+static int w1_max_slave_count = 10;
+static int w1_max_slave_ttl = 10;

module_param_named(timeout, w1_timeout, int, 0);
module_param_named(max_slave_count, w1_max_slave_count, int, 0);
module_param_named(slave_ttl, w1_max_slave_ttl, int, 0);

-DEFINE_SPINLOCK(w1_mlock);
-LIST_HEAD(w1_masters);
+static DEFINE_SPINLOCK(w1_mlock);
+static LIST_HEAD(w1_masters);
+static u32 w1_ids = 1;

static pid_t control_thread;
static int control_needs_exit;
@@ -475,7 +475,7 @@ static void w1_slave_detach(struct w1_sl
w1_netlink_send(sl->master, &msg);
}

-void w1_slave_found(struct w1_master *dev, u64 rn)
+static void w1_slave_found(struct w1_master *dev, u64 rn)
{
int slave_count;
struct w1_slave *slave;
@@ -594,7 +594,7 @@ void w1_search(struct w1_master *dev)
}


-int w1_control(void *data)
+static int w1_control(void *data)
{
struct w1_slave *slave, *nexts;
struct w1_master *master, *nextm;
@@ -654,7 +654,7 @@ int w1_control(void *data)
complete_and_exit(&w1_control_complete, 0);
}

-int w1_process(void *data)
+static int w1_process(void *data)
{
struct w1_master *dev = (struct w1_master *) data;
struct w1_slave *slave, *next;
@@ -703,6 +703,144 @@ int w1_process(void *data)
return 0;
}

+struct w1_master *w1_allocate_master_device(void)
+{
+ struct w1_master *dev;
+
+ /*
+ * We are in process context(kernel thread), so can sleep.
+ */
+ dev = kcalloc(1, sizeof(struct w1_master), GFP_KERNEL);
+ if (!dev) {
+ printk(KERN_ERR
+ "Failed to allocate %zd bytes for new w1 device.\n",
+ sizeof(struct w1_master));
+ return NULL;
+ }
+
+ dev->max_slave_count = w1_max_slave_count;
+ dev->kpid = -1;
+ dev->id = w1_ids++;
+ dev->slave_ttl = w1_max_slave_ttl;
+
+ atomic_set(&dev->refcnt, 2);
+
+ INIT_LIST_HEAD(&dev->slist);
+ init_MUTEX(&dev->mutex);
+
+ init_completion(&dev->dev_released);
+ init_completion(&dev->dev_exited);
+
+ dev->dev = w1_device;
+ snprintf(dev->dev.bus_id, sizeof(dev->dev.bus_id),
+ "w1_bus_master%u", dev->id);
+
+ dev->driver = &w1_driver;
+
+ dev->groups = 23;
+ dev->seq = 1;
+
+ return dev;
+}
+
+static void w1_free_dev(struct w1_master *dev)
+{
+ device_unregister(&dev->dev);
+ if (dev->nls && dev->nls->sk_socket)
+ sock_release(dev->nls->sk_socket);
+ memset(dev, 0, sizeof(struct w1_master));
+ kfree(dev);
+}
+
+int w1_add_master_device(struct w1_master *dev)
+{
+ int error;
+ struct w1_netlink_msg msg;
+
+ dev->nls = netlink_kernel_create(NETLINK_NFLOG, NULL);
+ if (!dev->nls) {
+ printk(KERN_ERR "Failed to create new netlink socket(%u) for w1 master %s.\n",
+ NETLINK_NFLOG, dev->dev.bus_id);
+ return -1;
+ }
+
+ error = device_register(&dev->dev);
+ if (error) {
+ printk(KERN_ERR "Failed to register master device. err=%d\n", error);
+ if (dev->nls && dev->nls->sk_socket)
+ sock_release(dev->nls->sk_socket);
+ return error;
+ }
+
+ 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);
+ error = dev->kpid;
+ goto err_out_free_dev;
+ }
+
+ error = w1_create_master_attributes(dev);
+ if (error)
+ goto err_out_kill_thread;
+
+ dev->initialized = 1;
+
+ spin_lock(&w1_mlock);
+ list_add(&dev->node, &w1_masters);
+ spin_unlock(&w1_mlock);
+
+ msg.id.mst.id = dev->id;
+ msg.id.mst.pid = dev->kpid;
+ msg.type = W1_MASTER_ADD;
+ w1_netlink_send(dev, &msg);
+
+ 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 error;
+}
+
+void w1_remove_master_device(struct w1_master *dev)
+{
+ int err;
+ struct w1_netlink_msg msg;
+
+ 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)) {
+ printk(KERN_INFO "Waiting for %s to become free: refcnt=%d.\n",
+ dev->name, atomic_read(&dev->refcnt));
+
+ if (msleep_interruptible(1000))
+ flush_signals(current);
+ }
+
+ msg.id.mst.id = dev->id;
+ msg.id.mst.pid = dev->kpid;
+ msg.type = W1_MASTER_REMOVE;
+ w1_netlink_send(dev, &msg);
+
+ w1_free_dev(dev);
+}
+
+
int w1_init(void)
{
int retval;
@@ -760,3 +898,7 @@ void w1_fini(void)

module_init(w1_init);
module_exit(w1_fini);
+
+EXPORT_SYMBOL(w1_allocate_master_device);
+EXPORT_SYMBOL(w1_add_master_device);
+EXPORT_SYMBOL(w1_remove_master_device);
Index: dtor/drivers/w1/w1_int.h
===================================================================
--- dtor.orig/drivers/w1/w1_int.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * w1_int.h
- *
- * Copyright (c) 2004 Evgeniy Polyakov <[email protected]>
- *
- *
- * 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 <linux/err.h>
-
-#include "w1.h"
-
-struct w1_master *w1_allocate_master_device(void);
-void w1_free_dev(struct w1_master *dev);
-int w1_add_master_device(struct w1_master *);
-void w1_remove_master_device(struct w1_master *);
-
-#endif /* __W1_INT_H */
Index: dtor/drivers/w1/w1.h
===================================================================
--- dtor.orig/drivers/w1/w1.h
+++ dtor/drivers/w1/w1.h
@@ -133,9 +133,10 @@ struct w1_master
struct sock *nls;
};

-int w1_create_master_attributes(struct w1_master *);
-void w1_destroy_master_attributes(struct w1_master *);
-void w1_search(struct w1_master *dev);
+struct w1_master *w1_allocate_master_device(void);
+int w1_add_master_device(struct w1_master *);
+void w1_remove_master_device(struct w1_master *);
+void w1_search(struct w1_master *);

#endif /* __KERNEL__ */

Index: dtor/drivers/w1/w1_smem.c
===================================================================
--- dtor.orig/drivers/w1/w1_smem.c
+++ dtor/drivers/w1/w1_smem.c
@@ -29,7 +29,6 @@

#include "w1.h"
#include "w1_io.h"
-#include "w1_int.h"
#include "w1_family.h"

MODULE_LICENSE("GPL");

2005-04-21 07:57:37

by Dmitry Torokhov

[permalink] [raw]
Subject: [RFC/PATCH 9/22] W1: drop custom hotplug over netlink notification

W1: drop custom-made hotplug over netlink notification
from w1 core. Standard hotplug mechanism should work
just fine (patch will follow).

Signed-off-by: Dmitry Torokhov <[email protected]>
---

drivers/w1/w1_netlink.c | 66 -----------------------------------------------
drivers/w1/w1_netlink.h | 57 ----------------------------------------
dtor/drivers/w1/Makefile | 2 -
dtor/drivers/w1/w1.c | 36 -------------------------
dtor/drivers/w1/w1.h | 3 --
5 files changed, 1 insertion(+), 163 deletions(-)

Index: dtor/drivers/w1/w1_netlink.h
===================================================================
--- dtor.orig/drivers/w1/w1_netlink.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * w1_netlink.h
- *
- * Copyright (c) 2003 Evgeniy Polyakov <[email protected]>
- *
- *
- * 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"
-
-enum w1_netlink_message_types {
- W1_SLAVE_ADD = 0,
- W1_SLAVE_REMOVE,
- W1_MASTER_ADD,
- W1_MASTER_REMOVE,
-};
-
-struct w1_netlink_msg
-{
- __u8 type;
- __u8 reserved[3];
- union
- {
- struct w1_reg_num id;
- __u64 w1_id;
- struct
- {
- __u32 id;
- __u32 pid;
- } mst;
- } id;
-};
-
-#ifdef __KERNEL__
-
-void w1_netlink_send(struct w1_master *, struct w1_netlink_msg *);
-
-#endif /* __KERNEL__ */
-#endif /* __W1_NETLINK_H */
Index: dtor/drivers/w1/w1.c
===================================================================
--- dtor.orig/drivers/w1/w1.c
+++ dtor/drivers/w1/w1.c
@@ -37,7 +37,6 @@
#include "w1_io.h"
#include "w1_log.h"
#include "w1_family.h"
-#include "w1_netlink.h"

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Evgeniy Polyakov <[email protected]>");
@@ -395,7 +394,6 @@ static int w1_attach_slave_device(struct
struct w1_slave *sl;
struct w1_family *f;
int err;
- struct w1_netlink_msg msg;

sl = kmalloc(sizeof(struct w1_slave), GFP_KERNEL);
if (!sl) {
@@ -442,17 +440,11 @@ static int w1_attach_slave_device(struct
sl->ttl = dev->slave_ttl;
dev->slave_count++;

- memcpy(&msg.id.id, rn, sizeof(msg.id.id));
- msg.type = W1_SLAVE_ADD;
- w1_netlink_send(dev, &msg);
-
return 0;
}

static void w1_slave_detach(struct w1_slave *sl)
{
- struct w1_netlink_msg msg;
-
dev_info(&sl->dev, "%s: detaching %s.\n", __func__, sl->name);

while (atomic_read(&sl->refcnt)) {
@@ -469,10 +461,6 @@ static void w1_slave_detach(struct w1_sl
device_remove_file(&sl->dev, &sl->attr_val);
device_unregister(&sl->dev);
w1_family_put(sl->family);
-
- memcpy(&msg.id.id, &sl->reg_num, sizeof(msg.id.id));
- msg.type = W1_SLAVE_REMOVE;
- w1_netlink_send(sl->master, &msg);
}

static void w1_slave_found(struct w1_master *dev, u64 rn)
@@ -746,29 +734,16 @@ struct w1_master *w1_allocate_master_dev
static void w1_free_dev(struct w1_master *dev)
{
device_unregister(&dev->dev);
- if (dev->nls && dev->nls->sk_socket)
- sock_release(dev->nls->sk_socket);
- memset(dev, 0, sizeof(struct w1_master));
kfree(dev);
}

int w1_add_master_device(struct w1_master *dev)
{
int error;
- struct w1_netlink_msg msg;
-
- dev->nls = netlink_kernel_create(NETLINK_NFLOG, NULL);
- if (!dev->nls) {
- printk(KERN_ERR "Failed to create new netlink socket(%u) for w1 master %s.\n",
- NETLINK_NFLOG, dev->dev.bus_id);
- return -1;
- }

error = device_register(&dev->dev);
if (error) {
printk(KERN_ERR "Failed to register master device. err=%d\n", error);
- if (dev->nls && dev->nls->sk_socket)
- sock_release(dev->nls->sk_socket);
return error;
}

@@ -791,11 +766,6 @@ int w1_add_master_device(struct w1_maste
list_add(&dev->node, &w1_masters);
spin_unlock(&w1_mlock);

- msg.id.mst.id = dev->id;
- msg.id.mst.pid = dev->kpid;
- msg.type = W1_MASTER_ADD;
- w1_netlink_send(dev, &msg);
-
return 0;

err_out_kill_thread:
@@ -815,7 +785,6 @@ err_out_free_dev:
void w1_remove_master_device(struct w1_master *dev)
{
int err;
- struct w1_netlink_msg msg;

dev->need_exit = 1;
err = kill_proc(dev->kpid, SIGTERM, 1);
@@ -832,11 +801,6 @@ void w1_remove_master_device(struct w1_m
flush_signals(current);
}

- msg.id.mst.id = dev->id;
- msg.id.mst.pid = dev->kpid;
- msg.type = W1_MASTER_REMOVE;
- w1_netlink_send(dev, &msg);
-
w1_free_dev(dev);
}

Index: dtor/drivers/w1/w1_netlink.c
===================================================================
--- dtor.orig/drivers/w1/w1_netlink.c
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * w1_netlink.c
- *
- * Copyright (c) 2003 Evgeniy Polyakov <[email protected]>
- *
- *
- * 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"
-
-#ifndef NETLINK_DISABLED
-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;
-
- if (!dev->nls)
- return;
-
- 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;
-}
-#else
-#warning Netlink support is disabled. Please compile with NET support enabled.
-
-void w1_netlink_send(struct w1_master *dev, struct w1_netlink_msg *msg)
-{
-}
-#endif
Index: dtor/drivers/w1/w1.h
===================================================================
--- dtor.orig/drivers/w1/w1.h
+++ dtor/drivers/w1/w1.h
@@ -42,8 +42,6 @@ struct w1_reg_num
#include <linux/completion.h>
#include <linux/device.h>

-#include <net/sock.h>
-
#include <asm/semaphore.h>

#include "w1_family.h"
@@ -130,7 +128,6 @@ struct w1_master
struct w1_bus_ops *bus_ops;

u32 seq, groups;
- struct sock *nls;
};

struct w1_master *w1_allocate_master_device(void);
Index: dtor/drivers/w1/Makefile
===================================================================
--- dtor.orig/drivers/w1/Makefile
+++ dtor/drivers/w1/Makefile
@@ -7,7 +7,7 @@ EXTRA_CFLAGS += -DNETLINK_DISABLED
endif

obj-$(CONFIG_W1) += wire.o
-wire-objs := w1.o w1_family.o w1_netlink.o w1_io.o
+wire-objs := w1.o w1_family.o w1_io.o

obj-$(CONFIG_W1_MATROX) += matrox_w1.o
obj-$(CONFIG_W1_THERM) += w1_therm.o

2005-04-21 08:00:14

by Dmitry Torokhov

[permalink] [raw]
Subject: [RFC/PATCH 10/22] W1: drop main control thread

W1: Drop control thread from w1 core, whatever it does can
also be done in the context of w1_remove_master_device.
Also, pin the module when registering new master device
to make sure that w1 core is not unloaded until last
device is gone. This simplifies logic a lot.

Signed-off-by: Dmitry Torokhov <[email protected]>
---

w1.c | 157 +++++++++++++++----------------------------------------------------
w1.h | 1
2 files changed, 36 insertions(+), 122 deletions(-)

Index: dtor/drivers/w1/w1.c
===================================================================
--- dtor.orig/drivers/w1/w1.c
+++ dtor/drivers/w1/w1.c
@@ -50,14 +50,8 @@ module_param_named(timeout, w1_timeout,
module_param_named(max_slave_count, w1_max_slave_count, int, 0);
module_param_named(slave_ttl, w1_max_slave_ttl, int, 0);

-static DEFINE_SPINLOCK(w1_mlock);
-static LIST_HEAD(w1_masters);
static u32 w1_ids = 1;

-static pid_t control_thread;
-static int control_needs_exit;
-static DECLARE_COMPLETION(w1_control_complete);
-
static int w1_master_match(struct device *dev, struct device_driver *drv)
{
return 1;
@@ -582,66 +576,6 @@ void w1_search(struct w1_master *dev)
}


-static int w1_control(void *data)
-{
- struct w1_slave *slave, *nexts;
- struct w1_master *master, *nextm;
- int err, have_to_wait = 0;
-
- daemonize("w1_control");
- allow_signal(SIGTERM);
-
- while (!control_needs_exit || have_to_wait) {
- have_to_wait = 0;
-
- try_to_freeze(PF_FREEZE);
- msleep_interruptible(w1_timeout * 1000);
-
- if (signal_pending(current))
- flush_signals(current);
-
- list_for_each_entry_safe(master, nextm, &w1_masters, node) {
-
- if (!control_needs_exit && !master->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 (!master->initialized) {
- have_to_wait = 1;
- continue;
- }
-
- spin_lock(&w1_mlock);
- list_del(&master->node);
- spin_unlock(&w1_mlock);
-
- if (control_needs_exit) {
- master->need_exit = 1;
-
- err = kill_proc(master->kpid, SIGTERM, 1);
- if (err)
- dev_err(&master->dev,
- "Failed to send signal to w1 kernel thread %d.\n",
- master->kpid);
- }
-
- wait_for_completion(&master->dev_exited);
-
- list_for_each_entry_safe(slave, nexts, &master->slist, node) {
- list_del(&slave->node);
- w1_slave_detach(slave);
- kfree(slave);
- }
- w1_destroy_master_attributes(master);
- atomic_dec(&master->refcnt);
- }
- }
-
- complete_and_exit(&w1_control_complete, 0);
-}
-
static int w1_process(void *data)
{
struct w1_master *dev = (struct w1_master *) data;
@@ -731,12 +665,22 @@ struct w1_master *w1_allocate_master_dev
return dev;
}

-static void w1_free_dev(struct w1_master *dev)
+static void w1_free_master_dev(struct w1_master *dev)
{
device_unregister(&dev->dev);
kfree(dev);
}

+static void w1_stop_master_device(struct w1_master *dev)
+{
+ 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);
+}
+
int w1_add_master_device(struct w1_master *dev)
{
int error;
@@ -762,36 +706,32 @@ int w1_add_master_device(struct w1_maste

dev->initialized = 1;

- spin_lock(&w1_mlock);
- list_add(&dev->node, &w1_masters);
- spin_unlock(&w1_mlock);
+ __module_get(THIS_MODULE);

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);
+ w1_stop_master_device(dev);

err_out_free_dev:
- w1_free_dev(dev);
+ w1_free_master_dev(dev);

return error;
}

void w1_remove_master_device(struct w1_master *dev)
{
- int err;
+ struct w1_slave *slave, *next;

- 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);
+ w1_stop_master_device(dev);
+
+ list_for_each_entry_safe(slave, next, &dev->slist, node) {
+ list_del(&slave->node);
+ w1_slave_detach(slave);
+ kfree(slave);
+ }
+
+ w1_destroy_master_attributes(dev);

while (atomic_read(&dev->refcnt)) {
printk(KERN_INFO "Waiting for %s to become free: refcnt=%d.\n",
@@ -801,61 +741,36 @@ void w1_remove_master_device(struct w1_m
flush_signals(current);
}

- w1_free_dev(dev);
+ w1_free_master_dev(dev);
+ module_put(THIS_MODULE);
}


int w1_init(void)
{
- int retval;
+ int error;

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;
+ error = bus_register(&w1_bus_type);
+ if (error) {
+ printk(KERN_ERR "Failed to register bus. err=%d.\n", error);
+ return error;
}

- retval = driver_register(&w1_driver);
- if (retval) {
+ error = driver_register(&w1_driver);
+ if (error) {
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;
+ "Failed to register master driver. err=%d.\n", error);
+ bus_unregister(&w1_bus_type);
+ return error;
}

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 *master, *next;
-
- list_for_each_entry_safe(master, next, &w1_masters, node)
- w1_remove_master_device(master);
-
- control_needs_exit = 1;
-
- wait_for_completion(&w1_control_complete);
-
driver_unregister(&w1_driver);
bus_unregister(&w1_bus_type);
}
Index: dtor/drivers/w1/w1.h
===================================================================
--- dtor.orig/drivers/w1/w1.h
+++ dtor/drivers/w1/w1.h
@@ -103,7 +103,6 @@ struct w1_bus_ops

struct w1_master
{
- struct list_head node;
unsigned char name[W1_MAXNAMELEN];
struct list_head slist;
int max_slave_count, slave_count;

2005-04-21 08:03:16

by Dmitry Torokhov

[permalink] [raw]
Subject: [RFC/PATCH 11/22] W1: move w1_search to the rest of IO code

W1: move w1_search function to w1_io.c to be with the rest of IO code.

Signed-off-by: Dmitry Torokhov <[email protected]>
---

w1.c | 87 --------------------------------------------------------------
w1.h | 1
w1_io.c | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
3 files changed, 88 insertions(+), 89 deletions(-)

Index: dtor/drivers/w1/w1.c
===================================================================
--- dtor.orig/drivers/w1/w1.c
+++ dtor/drivers/w1/w1.c
@@ -488,93 +488,6 @@ static void w1_slave_found(struct w1_mas
atomic_dec(&dev->refcnt);
}

-void w1_search(struct w1_master *dev)
-{
- u64 last, rn, tmp;
- int i, count = 0;
- int last_family_desc, last_zero, last_device;
- int search_bit, id_bit, comp_bit, desc_bit;
-
- 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
- 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_touch_bit(dev, 1);
- comp_bit = w1_touch_bit(dev, 1);
-
- 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.
- */
- if (dev->bus_ops->touch_bit)
- w1_touch_bit(dev, search_bit);
- else
- w1_write_bit(dev, search_bit);
-
- }
-#endif
-
- if (desc_bit == last_zero)
- last_device = 1;
-
- desc_bit = last_zero;
-
- w1_slave_found(dev, rn);
- }
-}
-

static int w1_process(void *data)
{
Index: dtor/drivers/w1/w1_io.c
===================================================================
--- dtor.orig/drivers/w1/w1_io.c
+++ dtor/drivers/w1/w1_io.c
@@ -178,13 +178,100 @@ u8 w1_calc_crc8(u8 * data, int len)
return crc;
}

+static void w1_search(struct w1_master *dev, w1_slave_found_callback slave_found_cb)
+{
+ u64 last, rn, tmp;
+ int i, count = 0;
+ int last_family_desc, last_zero, last_device;
+ int search_bit, id_bit, comp_bit, desc_bit;
+
+ 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
+ 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_touch_bit(dev, 1);
+ comp_bit = w1_touch_bit(dev, 1);
+
+ 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.
+ */
+ if (dev->bus_ops->touch_bit)
+ w1_touch_bit(dev, search_bit);
+ else
+ w1_write_bit(dev, search_bit);
+
+ }
+#endif
+
+ if (desc_bit == last_zero)
+ last_device = 1;
+
+ desc_bit = last_zero;
+
+ slave_found_cb(dev, rn);
+ }
+}
+
void w1_search_devices(struct w1_master *dev, w1_slave_found_callback cb)
{
dev->attempts++;
if (dev->bus_ops->search)
dev->bus_ops->search(dev, cb);
else
- w1_search(dev);
+ w1_search(dev, cb);
}

EXPORT_SYMBOL(w1_write_bit);
Index: dtor/drivers/w1/w1.h
===================================================================
--- dtor.orig/drivers/w1/w1.h
+++ dtor/drivers/w1/w1.h
@@ -132,7 +132,6 @@ struct w1_master
struct w1_master *w1_allocate_master_device(void);
int w1_add_master_device(struct w1_master *);
void w1_remove_master_device(struct w1_master *);
-void w1_search(struct w1_master *);

#endif /* __KERNEL__ */

2005-04-21 08:05:55

by Dmitry Torokhov

[permalink] [raw]
Subject: [RFC/PATCH 13/22] W1: cleanup master attributes handling

W1: clean-up master attribute implementation:
- drop unnecessary "w1_master" prefix from attribute names;
- do not acquire master->mutex when accessing attributes;
- move attribute code "closer" to the rest of master code.

Signed-off-by: Dmitry Torokhov <[email protected]>
---

w1.c | 111 +++++++++++++++++++++++++------------------------------------------
w1.h | 1
2 files changed, 44 insertions(+), 68 deletions(-)

Index: dtor/drivers/w1/w1.c
===================================================================
--- dtor.orig/drivers/w1/w1.c
+++ dtor/drivers/w1/w1.c
@@ -95,72 +95,6 @@ struct device w1_device = {
.release = &w1_master_release
};

-static ssize_t w1_master_attribute_show_name(struct device *dev, char *buf)
-{
- struct w1_master *md = container_of (dev, struct w1_master, dev);
- ssize_t count;
-
- if (down_interruptible (&md->mutex))
- return -EBUSY;
-
- count = sprintf(buf, "%s\n", md->name);
-
- up(&md->mutex);
-
- return count;
-}
-
-static ssize_t w1_master_attribute_show_timeout(struct device *dev, char *buf)
-{
- ssize_t count;
- count = sprintf(buf, "%d\n", w1_timeout);
- return count;
-}
-
-static ssize_t w1_master_attribute_show_max_slave_count(struct device *dev, char *buf)
-{
- struct w1_master *md = container_of(dev, struct w1_master, dev);
- ssize_t count;
-
- if (down_interruptible(&md->mutex))
- return -EBUSY;
-
- count = sprintf(buf, "%d\n", md->max_slave_count);
-
- up(&md->mutex);
- return count;
-}
-
-#define W1_MASTER_ATTR_RO(_name, _mode) \
- struct device_attribute w1_master_attribute_##_name = \
- __ATTR(w1_master_##_name, _mode, \
- w1_master_attribute_show_##_name, NULL)
-
-static W1_MASTER_ATTR_RO(name, S_IRUGO);
-static W1_MASTER_ATTR_RO(max_slave_count, S_IRUGO);
-static W1_MASTER_ATTR_RO(timeout, S_IRUGO);
-
-static struct attribute *w1_master_default_attrs[] = {
- &w1_master_attribute_name.attr,
- &w1_master_attribute_max_slave_count.attr,
- &w1_master_attribute_timeout.attr,
- NULL
-};
-
-static struct attribute_group w1_master_defattr_group = {
- .attrs = w1_master_default_attrs,
-};
-
-int w1_create_master_attributes(struct w1_master *master)
-{
- return sysfs_create_group(&master->dev.kobj, &w1_master_defattr_group);
-}
-
-void w1_destroy_master_attributes(struct w1_master *master)
-{
- sysfs_remove_group(&master->dev.kobj, &w1_master_defattr_group);
-}
-
static ssize_t w1_slave_attribute_show_family(struct device *dev, char *buf)
{
struct w1_slave *slave = to_w1_slave(dev);
@@ -460,6 +394,47 @@ static int w1_process(void *data)
return 0;
}

+static ssize_t w1_master_attribute_show_name(struct device *dev, char *buf)
+{
+ struct w1_master *master = to_w1_master(dev);
+
+ return sprintf(buf, "%s\n", master->name);
+}
+
+static ssize_t w1_master_attribute_show_timeout(struct device *dev, char *buf)
+{
+ ssize_t count;
+ count = sprintf(buf, "%d\n", w1_timeout);
+ return count;
+}
+
+static ssize_t w1_master_attribute_show_max_slave_count(struct device *dev, char *buf)
+{
+ struct w1_master *master = to_w1_master(dev);
+
+ return sprintf(buf, "%d\n", master->max_slave_count);
+}
+
+#define W1_MASTER_ATTR_RO(_name, _mode) \
+ struct device_attribute w1_master_attribute_##_name = \
+ __ATTR(_name, _mode, \
+ w1_master_attribute_show_##_name, NULL)
+
+static W1_MASTER_ATTR_RO(name, S_IRUGO);
+static W1_MASTER_ATTR_RO(max_slave_count, S_IRUGO);
+static W1_MASTER_ATTR_RO(timeout, S_IRUGO);
+
+static struct attribute *w1_master_default_attrs[] = {
+ &w1_master_attribute_name.attr,
+ &w1_master_attribute_max_slave_count.attr,
+ &w1_master_attribute_timeout.attr,
+ NULL
+};
+
+static struct attribute_group w1_master_defattr_group = {
+ .attrs = w1_master_default_attrs,
+};
+
struct w1_master *w1_allocate_master_device(void)
{
struct w1_master *dev;
@@ -535,7 +510,7 @@ int w1_add_master_device(struct w1_maste
goto err_out_free_dev;
}

- error = w1_create_master_attributes(dev);
+ error = sysfs_create_group(&dev->dev.kobj, &w1_master_defattr_group);
if (error)
goto err_out_kill_thread;

@@ -566,7 +541,7 @@ void w1_remove_master_device(struct w1_m
kfree(slave);
}

- w1_destroy_master_attributes(dev);
+ sysfs_remove_group(&dev->dev.kobj, &w1_master_defattr_group);

while (atomic_read(&dev->refcnt)) {
printk(KERN_INFO "Waiting for %s to become free: refcnt=%d.\n",
Index: dtor/drivers/w1/w1.h
===================================================================
--- dtor.orig/drivers/w1/w1.h
+++ dtor/drivers/w1/w1.h
@@ -127,6 +127,7 @@ struct w1_master

u32 seq, groups;
};
+#define to_w1_master(dev) container_of((dev), struct w1_master, dev)

struct w1_master *w1_allocate_master_device(void);
int w1_add_master_device(struct w1_master *);

2005-04-21 08:09:56

by Dmitry Torokhov

[permalink] [raw]
Subject: [RFC/PATCH 15/22] W1: add slave_ttl master attribute

W1: add slave_ttl attribute to w1 masters.

Signed-off-by: Dmitry Torokhov <[email protected]>
---

w1.c | 24 ++++++++++++++++++++++++
1 files changed, 24 insertions(+)

Index: dtor/drivers/w1/w1.c
===================================================================
--- dtor.orig/drivers/w1/w1.c
+++ dtor/drivers/w1/w1.c
@@ -447,6 +447,28 @@ w1_master_attribute_set_max_slave_count(
return 0;
}

+static ssize_t w1_master_attribute_show_slave_ttl(struct device *dev, char *buf)
+{
+ struct w1_master *master = to_w1_master(dev);
+
+ return sprintf(buf, "%d\n", master->slave_ttl);
+}
+
+static ssize_t
+w1_master_attribute_set_slave_ttl(struct device *dev, const char *buf, size_t n)
+{
+ struct w1_master *master = to_w1_master(dev);
+ int slave_ttl;
+
+ slave_ttl = simple_strtoul(buf, NULL, 10);
+ if (!slave_ttl)
+ return -EINVAL;
+
+ master->slave_ttl = slave_ttl;
+ return 0;
+}
+
+
#define W1_MASTER_ATTR_RO(_name, _mode) \
struct device_attribute w1_master_attribute_##_name = \
__ATTR(_name, _mode, \
@@ -461,11 +483,13 @@ w1_master_attribute_set_max_slave_count(
static W1_MASTER_ATTR_RO(name, S_IRUGO);
static W1_MASTER_ATTR_RW(max_slave_count, S_IWUSR | S_IRUGO);
static W1_MASTER_ATTR_RW(scan_interval, S_IWUSR | S_IRUGO);
+static W1_MASTER_ATTR_RW(slave_ttl, S_IWUSR | S_IRUGO);

static struct attribute *w1_master_default_attrs[] = {
&w1_master_attribute_name.attr,
&w1_master_attribute_max_slave_count.attr,
&w1_master_attribute_scan_interval.attr,
+ &w1_master_attribute_slave_ttl.attr,
NULL
};

2005-04-21 08:12:08

by Dmitry Torokhov

[permalink] [raw]
Subject: [RFC/PATCH 16/22] W1: cleanup masters refcounting & more

W1: clean-up master device implementation:
- get rid of separate refcount, rely on driver model to
enforce lifetime rules;
- use atomic to generate unique master IDs;
- drop unused fields.

Signed-off-by: Dmitry Torokhov <[email protected]>
---

w1.c | 263 ++++++++++++++++++++++++++-----------------------------------------
w1.h | 17 +---
2 files changed, 108 insertions(+), 172 deletions(-)

Index: dtor/drivers/w1/w1.h
===================================================================
--- dtor.orig/drivers/w1/w1.h
+++ dtor/drivers/w1/w1.h
@@ -103,30 +103,21 @@ struct w1_bus_ops

struct w1_master
{
+ void *private;
+
unsigned char name[W1_MAXNAMELEN];
struct list_head slist;
int max_slave_count;
int slave_ttl;
int scan_interval;
- int initialized;
- u32 id;
-
- atomic_t refcnt;
-
- void *private;

- int need_exit;
pid_t kpid;
- struct semaphore mutex;

- struct device_driver *driver;
struct device dev;
- struct completion dev_released;
- struct completion dev_exited;
+ struct completion thread_exited;
+ struct semaphore mutex;

struct w1_bus_ops *bus_ops;
-
- u32 seq, groups;
};
#define to_w1_master(dev) container_of((dev), struct w1_master, dev)

Index: dtor/drivers/w1/w1.c
===================================================================
--- dtor.orig/drivers/w1/w1.c
+++ dtor/drivers/w1/w1.c
@@ -50,49 +50,19 @@ module_param_named(scan_interval, w1_sca
module_param_named(max_slave_count, w1_max_slave_count, int, 0);
module_param_named(slave_ttl, w1_max_slave_ttl, int, 0);

-static u32 w1_ids = 1;
-
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 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,
+struct device_driver w1_master_driver = {
+ .name = "master",
.bus = &w1_bus_type,
- .bus_id = "w1 bus master",
- .driver = &w1_driver,
- .release = &w1_master_release
};

static ssize_t w1_slave_attribute_show_family(struct device *dev, char *buf)
@@ -166,7 +136,6 @@ static int __w1_attach_slave_device(stru
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;

@@ -346,52 +315,44 @@ static void w1_slave_found(struct w1_mas
w1_attach_slave_device(dev, reg_num);
}

-
-static int w1_process(void *data)
+static void w1_master_scan_slaves(struct w1_master *master)
{
- struct w1_master *dev = (struct w1_master *) data;
struct w1_slave *slave, *next;

- daemonize("%s", dev->name);
- allow_signal(SIGTERM);
-
- while (!dev->need_exit) {
- try_to_freeze(PF_FREEZE);
- msleep_interruptible(dev->scan_interval * 1000);
-
- if (signal_pending(current))
- flush_signals(current);
-
- if (dev->need_exit)
- break;
-
- if (!dev->initialized)
- continue;
-
- if (down_interruptible(&dev->mutex))
- continue;
+ if (down_interruptible(&master->mutex))
+ return;

- list_for_each_entry(slave, &dev->slist, node)
- clear_bit(W1_SLAVE_ACTIVE, &slave->flags);
+ list_for_each_entry(slave, &master->slist, node)
+ clear_bit(W1_SLAVE_ACTIVE, &slave->flags);

- w1_search_devices(dev, w1_slave_found);
+ w1_search_devices(master, w1_slave_found);

- list_for_each_entry_safe(slave, next, &dev->slist, node) {
+ list_for_each_entry_safe(slave, next, &master->slist, node) {

- if (!test_bit(W1_SLAVE_ACTIVE, &slave->flags) &&
- !--slave->ttl) {
- list_del(&slave->node);
- w1_slave_detach(slave);
- kfree(slave);
- }
+ if (!test_bit(W1_SLAVE_ACTIVE, &slave->flags) &&
+ !--slave->ttl) {
+ list_del(&slave->node);
+ w1_slave_detach(slave);
+ kfree(slave);
}
- up(&dev->mutex);
}
+ up(&master->mutex);
+}
+
+static int w1_process(void *data)
+{
+ struct w1_master *master = (struct w1_master *) data;

- atomic_dec(&dev->refcnt);
- complete_and_exit(&dev->dev_exited, 0);
+ daemonize("%s", master->dev.bus_id);
+ allow_signal(SIGTERM);

- return 0;
+ do {
+ w1_master_scan_slaves(master);
+ msleep_interruptible(master->scan_interval * 1000);
+ try_to_freeze(PF_FREEZE);
+ } while (!signal_pending(current));
+
+ complete_and_exit(&master->thread_exited, 0);
}

static ssize_t w1_master_attribute_show_name(struct device *dev, char *buf)
@@ -497,128 +458,110 @@ static struct attribute_group w1_master_
.attrs = w1_master_default_attrs,
};

+static void w1_release_master_device(struct device *dev)
+{
+ struct w1_master *master = to_w1_master(dev);
+
+ kfree(master);
+ module_put(THIS_MODULE);
+}
+
struct w1_master *w1_allocate_master_device(void)
{
- struct w1_master *dev;
+ struct w1_master *master;

- /*
- * We are in process context(kernel thread), so can sleep.
- */
- dev = kcalloc(1, sizeof(struct w1_master), GFP_KERNEL);
- if (!dev) {
+ master = kcalloc(1, sizeof(struct w1_master), GFP_KERNEL);
+ if (!master) {
printk(KERN_ERR
- "Failed to allocate %zd bytes for new w1 device.\n",
- sizeof(struct w1_master));
+ "w1: Failed to allocate %zd bytes for new w1 device.\n",
+ sizeof(struct w1_master));
return NULL;
}

- dev->max_slave_count = w1_max_slave_count;
- dev->kpid = -1;
- dev->id = w1_ids++;
- dev->slave_ttl = w1_max_slave_ttl;
-
- atomic_set(&dev->refcnt, 2);
-
- INIT_LIST_HEAD(&dev->slist);
- init_MUTEX(&dev->mutex);
-
- init_completion(&dev->dev_released);
- init_completion(&dev->dev_exited);
-
- dev->dev = w1_device;
- snprintf(dev->dev.bus_id, sizeof(dev->dev.bus_id),
- "w1_bus_master%u", dev->id);
+ master->max_slave_count = w1_max_slave_count;
+ master->slave_ttl = w1_max_slave_ttl;
+ master->scan_interval = w1_scan_interval;

- dev->driver = &w1_driver;
-
- dev->groups = 23;
- dev->seq = 1;
-
- return dev;
-}
-
-static void w1_free_master_dev(struct w1_master *dev)
-{
- device_unregister(&dev->dev);
- kfree(dev);
-}
+ INIT_LIST_HEAD(&master->slist);
+ init_MUTEX(&master->mutex);
+ init_completion(&master->thread_exited);

-static void w1_stop_master_device(struct w1_master *dev)
-{
- 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);
+ return master;
}

-int w1_add_master_device(struct w1_master *dev)
+int w1_add_master_device(struct w1_master *master)
{
+ static atomic_t master_no = ATOMIC_INIT(0);
int error;

- error = device_register(&dev->dev);
+ snprintf(master->dev.bus_id, sizeof(master->dev.bus_id),
+ "master%lu", (unsigned long)atomic_inc_return(&master_no));
+ master->dev.bus = &w1_bus_type;
+ master->dev.release = w1_release_master_device;
+ master->dev.driver = &w1_master_driver;
+
+ error = device_register(&master->dev);
if (error) {
- printk(KERN_ERR "Failed to register master device. err=%d\n", error);
+ printk(KERN_ERR
+ "w1: Failed to register master device. err=%d\n",
+ error);
return error;
}

- 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);
- error = dev->kpid;
- goto err_out_free_dev;
- }
-
- error = sysfs_create_group(&dev->dev.kobj, &w1_master_defattr_group);
- if (error)
- goto err_out_kill_thread;
-
- dev->initialized = 1;
-
__module_get(THIS_MODULE);

- return 0;
+ error = sysfs_create_group(&master->dev.kobj, &w1_master_defattr_group);
+ if (error) {
+ printk(KERN_ERR
+ "w1: Failed to create master attributes, err=%d\n",
+ error);
+ goto err_out_unregister;
+ }

-err_out_kill_thread:
- w1_stop_master_device(dev);
+ master->kpid = kernel_thread(&w1_process, master, 0);
+ if (master->kpid < 0) {
+ printk(KERN_ERR
+ "w1: Failed to create new kernel thread, err=%d\n",
+ master->kpid);
+ error = master->kpid;
+ goto err_out_remove_attrs;
+ }

-err_out_free_dev:
- w1_free_master_dev(dev);
+ return 0;

+err_out_remove_attrs:
+ sysfs_remove_group(&master->dev.kobj, &w1_master_defattr_group);
+err_out_unregister:
+ device_unregister(&master->dev);
return error;
}

-void w1_remove_master_device(struct w1_master *dev)
+static void w1_stop_master_device(struct w1_master *master)
+{
+ if (kill_proc(master->kpid, SIGTERM, 1))
+ printk(KERN_ERR
+ "w1: Failed to send signal to w1 kernel thread %d.\n",
+ master->kpid);
+ wait_for_completion(&master->thread_exited);
+}
+
+void w1_remove_master_device(struct w1_master *master)
{
struct w1_slave *slave, *next;

- w1_stop_master_device(dev);
+ w1_stop_master_device(master);

- list_for_each_entry_safe(slave, next, &dev->slist, node) {
+ list_for_each_entry_safe(slave, next, &master->slist, node) {
list_del(&slave->node);
w1_slave_detach(slave);
kfree(slave);
}

- sysfs_remove_group(&dev->dev.kobj, &w1_master_defattr_group);
-
- while (atomic_read(&dev->refcnt)) {
- printk(KERN_INFO "Waiting for %s to become free: refcnt=%d.\n",
- dev->name, atomic_read(&dev->refcnt));
-
- if (msleep_interruptible(1000))
- flush_signals(current);
- }
-
- w1_free_master_dev(dev);
- module_put(THIS_MODULE);
+ sysfs_remove_group(&master->dev.kobj, &w1_master_defattr_group);
+ device_unregister(&master->dev);
}

-
-int w1_init(void)
+static int w1_init(void)
{
int error;

@@ -626,14 +569,16 @@ int w1_init(void)

error = bus_register(&w1_bus_type);
if (error) {
- printk(KERN_ERR "Failed to register bus. err=%d.\n", error);
+ printk(KERN_ERR "w1: Failed to register bus. err=%d.\n",
+ error);
return error;
}

- error = driver_register(&w1_driver);
+ error = driver_register(&w1_master_driver);
if (error) {
printk(KERN_ERR
- "Failed to register master driver. err=%d.\n", error);
+ "w1: Failed to register master driver. err=%d.\n",
+ error);
bus_unregister(&w1_bus_type);
return error;
}
@@ -641,14 +586,14 @@ int w1_init(void)
return 0;
}

-void w1_fini(void)
+static void w1_exit(void)
{
- driver_unregister(&w1_driver);
+ driver_unregister(&w1_master_driver);
bus_unregister(&w1_bus_type);
}

module_init(w1_init);
-module_exit(w1_fini);
+module_exit(w1_exit);

EXPORT_SYMBOL(w1_allocate_master_device);
EXPORT_SYMBOL(w1_add_master_device);

2005-04-21 08:15:56

by Dmitry Torokhov

[permalink] [raw]
Subject: [RFC/PATCH 17/22] W1: cleanup slave refcounting & more

W1: clean-up slave device implementation:
- get rid of separate refcount, rely on driver model to
enforce lifetime rules;
- pin w1 module until slave device is registered with sysfs
to make sure W1 core stays loaded.
- drop 'name' attribute as we already have it in bus_id.

Signed-off-by: Dmitry Torokhov <[email protected]>
---

w1.c | 165 ++++++++++++++++++++++++------------------------------------
w1.h | 3 -
w1_family.c | 2
w1_family.h | 2
w1_smem.c | 18 ------
w1_therm.c | 20 -------
6 files changed, 71 insertions(+), 139 deletions(-)

Index: dtor/drivers/w1/w1.c
===================================================================
--- dtor.orig/drivers/w1/w1.c
+++ dtor/drivers/w1/w1.c
@@ -108,9 +108,6 @@ static ssize_t w1_default_read_bin(struc
return sprintf(buf, "No family registered.\n");
}

-static struct device_attribute w1_slave_attribute =
- __ATTR(name, S_IRUGO, w1_default_read_name, NULL);
-
static struct device_attribute w1_slave_attribute_val =
__ATTR(value, S_IRUGO, w1_default_read_name, NULL);

@@ -126,166 +123,138 @@ static struct bin_attribute w1_slave_bin

static void w1_slave_release(struct device *dev)
{
- struct w1_slave *sl = container_of(dev, struct w1_slave, dev);
+ struct w1_slave *slave = to_w1_slave(dev);

- complete(&sl->dev_released);
+ w1_family_put(slave->family);
+ kfree(slave);
+ module_put(THIS_MODULE);
}

-static int __w1_attach_slave_device(struct w1_slave *sl)
+static int __w1_attach_slave_device(struct w1_slave *slave)
{
int err;

- sl->dev.parent = &sl->master->dev;
- sl->dev.bus = &w1_bus_type;
- sl->dev.release = &w1_slave_release;
+ slave->dev.parent = &slave->master->dev;
+ slave->dev.bus = &w1_bus_type;
+ slave->dev.release = &w1_slave_release;

- snprintf(&sl->dev.bus_id[0], sizeof(sl->dev.bus_id),
- "%02x-%012llx",
- (unsigned int) sl->reg_num.family,
- (unsigned long long) sl->reg_num.id);
- snprintf (&sl->name[0], sizeof(sl->name),
+ snprintf(&slave->dev.bus_id[0], sizeof(slave->dev.bus_id),
"%02x-%012llx",
- (unsigned int) sl->reg_num.family,
- (unsigned long long) sl->reg_num.id);
+ (unsigned int) slave->reg_num.family,
+ (unsigned long long) slave->reg_num.id);

- dev_dbg(&sl->dev, "%s: registering %s.\n", __func__,
- &sl->dev.bus_id[0]);
+ dev_dbg(&slave->dev, "%s: registering %s.\n", __func__,
+ &slave->dev.bus_id[0]);

- err = device_register(&sl->dev);
+ err = device_register(&slave->dev);
if (err < 0) {
- dev_err(&sl->dev,
+ dev_err(&slave->dev,
"Device registration [%s] failed. err=%d\n",
- sl->dev.bus_id, err);
+ slave->dev.bus_id, err);
return err;
}

- memcpy(&sl->attr_bin, &w1_slave_bin_attribute, sizeof(sl->attr_bin));
- memcpy(&sl->attr_name, &w1_slave_attribute, sizeof(sl->attr_name));
- memcpy(&sl->attr_val, &w1_slave_attribute_val, sizeof(sl->attr_val));
-
- sl->attr_bin.read = sl->family->fops->rbin;
- sl->attr_name.show = sl->family->fops->rname;
- sl->attr_val.show = sl->family->fops->rval;
- sl->attr_val.attr.name = sl->family->fops->rvalname;
+ __module_get(THIS_MODULE);

- err = device_create_file(&sl->dev, &sl->attr_name);
- 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;
- }
+ memcpy(&slave->attr_bin, &w1_slave_bin_attribute, sizeof(slave->attr_bin));
+ memcpy(&slave->attr_val, &w1_slave_attribute_val, sizeof(slave->attr_val));

- err = device_create_file(&sl->dev, &sl->attr_val);
+ slave->attr_bin.read = slave->family->fops->rbin;
+ slave->attr_val.show = slave->family->fops->rval;
+ slave->attr_val.attr.name = slave->family->fops->rvalname;
+
+ err = device_create_file(&slave->dev, &slave->attr_val);
if (err < 0) {
- dev_err(&sl->dev,
+ dev_err(&slave->dev,
"sysfs file creation for [%s] failed. err=%d\n",
- sl->dev.bus_id, err);
- device_remove_file(&sl->dev, &sl->attr_name);
- device_unregister(&sl->dev);
+ slave->dev.bus_id, err);
+ device_unregister(&slave->dev);
return err;
}

- err = sysfs_create_bin_file(&sl->dev.kobj, &sl->attr_bin);
+ err = sysfs_create_bin_file(&slave->dev.kobj, &slave->attr_bin);
if (err < 0) {
- dev_err(&sl->dev,
+ dev_err(&slave->dev,
"sysfs file creation for [%s] failed. err=%d\n",
- sl->dev.bus_id, err);
- device_remove_file(&sl->dev, &sl->attr_name);
- device_remove_file(&sl->dev, &sl->attr_val);
- device_unregister(&sl->dev);
+ slave->dev.bus_id, err);
+ device_remove_file(&slave->dev, &slave->attr_val);
+ device_unregister(&slave->dev);
return err;
}

- err = sysfs_create_group(&sl->dev.kobj, &w1_slave_defattr_group);
+ err = sysfs_create_group(&slave->dev.kobj, &w1_slave_defattr_group);
if (err < 0) {
- dev_err(&sl->dev,
+ dev_err(&slave->dev,
"sysfs group creation for [%s] failed. err=%d\n",
- sl->dev.bus_id, err);
- sysfs_remove_bin_file(&sl->dev.kobj, &sl->attr_bin);
- device_remove_file(&sl->dev, &sl->attr_name);
- device_remove_file(&sl->dev, &sl->attr_val);
- device_unregister(&sl->dev);
+ slave->dev.bus_id, err);
+ sysfs_remove_bin_file(&slave->dev.kobj, &slave->attr_bin);
+ device_remove_file(&slave->dev, &slave->attr_val);
+ device_unregister(&slave->dev);
return err;
}

- list_add_tail(&sl->node, &sl->master->slist);
+ list_add_tail(&slave->node, &slave->master->slist);

return 0;
}

-static int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn)
+static int w1_attach_slave_device(struct w1_master *master, struct w1_reg_num *rn)
{
- struct w1_slave *sl;
+ struct w1_slave *slave;
struct w1_family *f;
int err;

- sl = kmalloc(sizeof(struct w1_slave), GFP_KERNEL);
- if (!sl) {
- dev_err(&dev->dev,
+ slave = kcalloc(1, sizeof(struct w1_slave), GFP_KERNEL);
+ if (!slave) {
+ dev_err(&master->dev,
"%s: failed to allocate new slave device.\n",
__func__);
return -ENOMEM;
}

- memset(sl, 0, sizeof(*sl));
-
- sl->master = dev;
- set_bit(W1_SLAVE_ACTIVE, &sl->flags);
-
- memcpy(&sl->reg_num, rn, sizeof(sl->reg_num));
- atomic_set(&sl->refcnt, 0);
- init_completion(&sl->dev_released);
+ slave->master = master;
+ slave->reg_num = *rn;
+ set_bit(W1_SLAVE_ACTIVE, &slave->flags);

spin_lock(&w1_flock);
f = w1_family_registered(rn->family);
if (!f) {
spin_unlock(&w1_flock);
- dev_info(&dev->dev, "Family %x for %02x.%012llx.%02x is not registered.\n",
- rn->family, rn->family,
- (unsigned long long)rn->id, rn->crc);
- kfree(sl);
+ dev_info(&master->dev,
+ "Family %x for %02x.%012llx.%02x is not registered.\n",
+ rn->family, rn->family,
+ (unsigned long long)rn->id, rn->crc);
+ kfree(slave);
return -ENODEV;
}
__w1_family_get(f);
spin_unlock(&w1_flock);

- sl->family = f;
+ slave->family = f;

-
- err = __w1_attach_slave_device(sl);
+ err = __w1_attach_slave_device(slave);
if (err < 0) {
- dev_err(&dev->dev, "%s: Attaching %s failed.\n", __func__,
- sl->name);
- w1_family_put(sl->family);
- kfree(sl);
+ dev_err(&master->dev, "%s: Attaching %s failed.\n", __func__,
+ slave->dev.bus_id);
+ w1_family_put(slave->family);
+ kfree(slave);
return err;
}

- sl->ttl = dev->slave_ttl;
+ slave->ttl = master->slave_ttl;

return 0;
}

-static void w1_slave_detach(struct w1_slave *sl)
+static void w1_slave_detach(struct w1_slave *slave)
{
- dev_info(&sl->dev, "%s: detaching %s.\n", __func__, sl->name);
+ dev_info(&slave->dev, "%s: detaching %s.\n",
+ __func__, slave->dev.bus_id);

- while (atomic_read(&sl->refcnt)) {
- printk(KERN_INFO "Waiting for %s to become free: refcnt=%d.\n",
- sl->name, atomic_read(&sl->refcnt));
-
- if (msleep_interruptible(1000))
- flush_signals(current);
- }
-
- sysfs_remove_group(&sl->dev.kobj, &w1_slave_defattr_group);
- sysfs_remove_bin_file(&sl->dev.kobj, &sl->attr_bin);
- device_remove_file(&sl->dev, &sl->attr_name);
- device_remove_file(&sl->dev, &sl->attr_val);
- device_unregister(&sl->dev);
- w1_family_put(sl->family);
+ sysfs_remove_group(&slave->dev.kobj, &w1_slave_defattr_group);
+ sysfs_remove_bin_file(&slave->dev.kobj, &slave->attr_bin);
+ device_remove_file(&slave->dev, &slave->attr_val);
+ device_unregister(&slave->dev);
}

static void w1_slave_found(struct w1_master *dev, u64 rn)
@@ -333,7 +302,6 @@ static void w1_master_scan_slaves(struct
!--slave->ttl) {
list_del(&slave->node);
w1_slave_detach(slave);
- kfree(slave);
}
}
up(&master->mutex);
@@ -554,7 +522,6 @@ void w1_remove_master_device(struct w1_m
list_for_each_entry_safe(slave, next, &master->slist, node) {
list_del(&slave->node);
w1_slave_detach(slave);
- kfree(slave);
}

sysfs_remove_group(&master->dev.kobj, &w1_master_defattr_group);
Index: dtor/drivers/w1/w1.h
===================================================================
--- dtor.orig/drivers/w1/w1.h
+++ dtor/drivers/w1/w1.h
@@ -62,10 +62,8 @@ struct w1_reg_num

struct w1_slave
{
- unsigned char name[W1_MAXNAMELEN];
struct list_head node;
struct w1_reg_num reg_num;
- atomic_t refcnt;
u8 rom[9];
unsigned long flags;
int ttl;
@@ -73,7 +71,6 @@ struct w1_slave
struct w1_master *master;
struct w1_family *family;
struct device dev;
- struct completion dev_released;

struct bin_attribute attr_bin;
struct device_attribute attr_name, attr_val;
Index: dtor/drivers/w1/w1_therm.c
===================================================================
--- dtor.orig/drivers/w1/w1_therm.c
+++ dtor/drivers/w1/w1_therm.c
@@ -41,24 +41,15 @@ static u8 bad_roms[][9] = {
{}
};

-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 inline int w1_convert_temp(u8 rom[9])
{
int t, h;
@@ -102,12 +93,8 @@ static ssize_t w1_therm_read_bin(struct
u8 rom[9], crc, verdict;
int i, max_trying = 10;

- atomic_inc(&sl->refcnt);
- smp_mb__after_atomic_inc();
- if (down_interruptible(&sl->master->mutex)) {
- count = 0;
- goto out_dec;
- }
+ if (down_interruptible(&sl->master->mutex))
+ return 0;

if (off > W1_SLAVE_DATA_SIZE) {
count = 0;
@@ -178,9 +165,6 @@ static ssize_t w1_therm_read_bin(struct
count += sprintf(buf + count, "t=%d\n", w1_convert_temp(rom));
out:
up(&dev->mutex);
-out_dec:
- smp_mb__before_atomic_inc();
- atomic_dec(&sl->refcnt);

return count;
}
Index: dtor/drivers/w1/w1_smem.c
===================================================================
--- dtor.orig/drivers/w1/w1_smem.c
+++ dtor/drivers/w1/w1_smem.c
@@ -35,24 +35,15 @@ MODULE_LICENSE("GPL");
MODULE_AUTHOR("Evgeniy Polyakov <[email protected]>");
MODULE_DESCRIPTION("Driver for 1-wire Dallas network protocol, 64bit memory family.");

-static ssize_t w1_smem_read_name(struct device *, char *);
static ssize_t w1_smem_read_val(struct device *, char *);
static ssize_t w1_smem_read_bin(struct kobject *, char *, loff_t, size_t);

static struct w1_family_ops w1_smem_fops = {
- .rname = &w1_smem_read_name,
.rbin = &w1_smem_read_bin,
.rval = &w1_smem_read_val,
.rvalname = "id",
};

-static ssize_t w1_smem_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_smem_read_val(struct device *dev, char *buf)
{
struct w1_slave *sl = container_of(dev, struct w1_slave, dev);
@@ -72,11 +63,8 @@ static ssize_t w1_smem_read_bin(struct k
struct w1_slave, dev);
int i;

- atomic_inc(&sl->refcnt);
- if (down_interruptible(&sl->master->mutex)) {
- count = 0;
- goto out_dec;
- }
+ if (down_interruptible(&sl->master->mutex))
+ return 0;

if (off > W1_SLAVE_DATA_SIZE) {
count = 0;
@@ -92,8 +80,6 @@ static ssize_t w1_smem_read_bin(struct k

out:
up(&sl->master->mutex);
-out_dec:
- atomic_dec(&sl->refcnt);

return count;
}
Index: dtor/drivers/w1/w1_family.c
===================================================================
--- dtor.orig/drivers/w1/w1_family.c
+++ dtor/drivers/w1/w1_family.c
@@ -30,7 +30,7 @@ static LIST_HEAD(w1_families);

static int w1_check_family(struct w1_family *f)
{
- if (!f->fops->rname || !f->fops->rbin || !f->fops->rval || !f->fops->rvalname)
+ if (!f->fops->rbin || !f->fops->rval || !f->fops->rvalname)
return -EINVAL;

return 0;
Index: dtor/drivers/w1/w1_family.h
===================================================================
--- dtor.orig/drivers/w1/w1_family.h
+++ dtor/drivers/w1/w1_family.h
@@ -34,9 +34,7 @@

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];
};

2005-04-21 08:05:56

by Dmitry Torokhov

[permalink] [raw]
Subject: [RFC/PATCH 12/22] W1: drop unneeded master attributes

W1: get rid of unneeded master device attributes:
- 'pointer' and 'attempts' are meaningless for userspace;
- information provided by 'slaves' and 'slave_count' can be
gathered from other sysfs bits;
- w1_slave_found has to be rearranged now that slave_count
field is gone.

Signed-off-by: Dmitry Torokhov <[email protected]>
---

w1.c | 108 ++++++++--------------------------------------------------------
w1.h | 3 -
w1_io.c | 1
3 files changed, 16 insertions(+), 96 deletions(-)

Index: dtor/drivers/w1/w1.c
===================================================================
--- dtor.orig/drivers/w1/w1.c
+++ dtor/drivers/w1/w1.c
@@ -110,20 +110,6 @@ static ssize_t w1_master_attribute_show_
return count;
}

-static ssize_t w1_master_attribute_show_pointer(struct device *dev, char *buf)
-{
- struct w1_master *md = container_of(dev, struct w1_master, dev);
- ssize_t count;
-
- if (down_interruptible(&md->mutex))
- return -EBUSY;
-
- count = sprintf(buf, "0x%p\n", md->private);
-
- up(&md->mutex);
- return count;
-}
-
static ssize_t w1_master_attribute_show_timeout(struct device *dev, char *buf)
{
ssize_t count;
@@ -145,76 +131,19 @@ static ssize_t w1_master_attribute_show_
return count;
}

-static ssize_t w1_master_attribute_show_attempts(struct device *dev, char *buf)
-{
- struct w1_master *md = container_of(dev, struct w1_master, dev);
- ssize_t count;
-
- if (down_interruptible(&md->mutex))
- return -EBUSY;
-
- count = sprintf(buf, "%lu\n", md->attempts);
-
- up(&md->mutex);
- return count;
-}
-
-static ssize_t w1_master_attribute_show_slave_count(struct device *dev, char *buf)
-{
- struct w1_master *md = container_of(dev, struct w1_master, dev);
- ssize_t count;
-
- if (down_interruptible(&md->mutex))
- return -EBUSY;
-
- count = sprintf(buf, "%d\n", md->slave_count);
-
- up(&md->mutex);
- return count;
-}
-
-static ssize_t w1_master_attribute_show_slaves(struct device *dev, char *buf)
-
-{
- struct w1_master *md = container_of(dev, struct w1_master, dev);
- struct w1_slave *slave;
- int c = PAGE_SIZE;
-
- if (down_interruptible(&md->mutex))
- return -EBUSY;
-
- if (md->slave_count == 0)
- c -= snprintf(buf + PAGE_SIZE - c, c, "not found.\n");
- else
- list_for_each_entry(slave, &md->slist, node)
- c -= snprintf(buf + PAGE_SIZE - c, c, "%s\n", slave->name);
-
- up(&md->mutex);
-
- return PAGE_SIZE - c;
-}
-
#define W1_MASTER_ATTR_RO(_name, _mode) \
struct device_attribute w1_master_attribute_##_name = \
__ATTR(w1_master_##_name, _mode, \
w1_master_attribute_show_##_name, NULL)

static W1_MASTER_ATTR_RO(name, S_IRUGO);
-static W1_MASTER_ATTR_RO(slaves, S_IRUGO);
-static W1_MASTER_ATTR_RO(slave_count, S_IRUGO);
static W1_MASTER_ATTR_RO(max_slave_count, S_IRUGO);
-static W1_MASTER_ATTR_RO(attempts, S_IRUGO);
static W1_MASTER_ATTR_RO(timeout, S_IRUGO);
-static W1_MASTER_ATTR_RO(pointer, S_IRUGO);

static struct attribute *w1_master_default_attrs[] = {
&w1_master_attribute_name.attr,
- &w1_master_attribute_slaves.attr,
- &w1_master_attribute_slave_count.attr,
&w1_master_attribute_max_slave_count.attr,
- &w1_master_attribute_attempts.attr,
&w1_master_attribute_timeout.attr,
- &w1_master_attribute_pointer.attr,
NULL
};

@@ -432,7 +361,6 @@ static int w1_attach_slave_device(struct
}

sl->ttl = dev->slave_ttl;
- dev->slave_count++;

return 0;
}
@@ -459,33 +387,29 @@ static void w1_slave_detach(struct w1_sl

static void w1_slave_found(struct w1_master *dev, u64 rn)
{
- int slave_count;
struct w1_slave *slave;
- struct w1_reg_num *tmp;
+ struct w1_reg_num *reg_num;
+ u64 le_rn;

- atomic_inc(&dev->refcnt);
+ if (!rn)
+ return;

- tmp = (struct w1_reg_num *) &rn;
+ reg_num = (struct w1_reg_num *) &rn;
+ le_rn = cpu_to_le64(rn);
+ if (w1_calc_crc8((u8 *)&le_rn, 7) != reg_num->crc)
+ return; /* bad CRC */

- slave_count = 0;
list_for_each_entry(slave, &dev->slist, node) {

- if (slave->reg_num.family == tmp->family &&
- slave->reg_num.id == tmp->id &&
- slave->reg_num.crc == tmp->crc) {
+ if (slave->reg_num.family == reg_num->family &&
+ slave->reg_num.id == reg_num->id) {
set_bit(W1_SLAVE_ACTIVE, &slave->flags);
- break;
+ slave->ttl = dev->slave_ttl;
+ return;
}
- slave_count++;
}

- if (slave_count == dev->slave_count && rn) {
- tmp = cpu_to_le64(rn);
- if (((rn >> 56) & 0xff) == w1_calc_crc8((u8 *)&tmp, 7))
- w1_attach_slave_device(dev, (struct w1_reg_num *) &rn);
- }
-
- atomic_dec(&dev->refcnt);
+ w1_attach_slave_device(dev, reg_num);
}


@@ -520,13 +444,11 @@ static int w1_process(void *data)

list_for_each_entry_safe(slave, next, &dev->slist, node) {

- if (test_bit(W1_SLAVE_ACTIVE, &slave->flags))
- slave->ttl = dev->slave_ttl;
- else if (!--slave->ttl) {
+ if (!test_bit(W1_SLAVE_ACTIVE, &slave->flags) &&
+ !--slave->ttl) {
list_del(&slave->node);
w1_slave_detach(slave);
kfree(slave);
- dev->slave_count--;
}
}
up(&dev->mutex);
Index: dtor/drivers/w1/w1_io.c
===================================================================
--- dtor.orig/drivers/w1/w1_io.c
+++ dtor/drivers/w1/w1_io.c
@@ -267,7 +267,6 @@ static void w1_search(struct w1_master *

void w1_search_devices(struct w1_master *dev, w1_slave_found_callback cb)
{
- dev->attempts++;
if (dev->bus_ops->search)
dev->bus_ops->search(dev, cb);
else
Index: dtor/drivers/w1/w1.h
===================================================================
--- dtor.orig/drivers/w1/w1.h
+++ dtor/drivers/w1/w1.h
@@ -105,8 +105,7 @@ struct w1_master
{
unsigned char name[W1_MAXNAMELEN];
struct list_head slist;
- int max_slave_count, slave_count;
- unsigned long attempts;
+ int max_slave_count;
int slave_ttl;
int initialized;
u32 id;

2005-04-21 08:21:12

by Dmitry Torokhov

[permalink] [raw]
Subject: [RFC/PATCH 14/22] W1: rename timeout to scan_interval

W1: more master attributes changes:
- rename timeout parameter/attribute to scan_interval to better
reflect its purpose;
- make scan_timeout be a per-device attribute and allow changing
it from userspace via sysfs;
- allow changing max_slave_count it from userspace as well.

Signed-off-by: Dmitry Torokhov <[email protected]>
---

w1.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++++-----------
w1.h | 1 +
2 files changed, 50 insertions(+), 11 deletions(-)

Index: dtor/drivers/w1/w1.c
===================================================================
--- dtor.orig/drivers/w1/w1.c
+++ dtor/drivers/w1/w1.c
@@ -42,11 +42,11 @@ MODULE_LICENSE("GPL");
MODULE_AUTHOR("Evgeniy Polyakov <[email protected]>");
MODULE_DESCRIPTION("Driver for 1-wire Dallas network protocol.");

-static int w1_timeout = 10;
+static int w1_scan_interval = 10;
static int w1_max_slave_count = 10;
static int w1_max_slave_ttl = 10;

-module_param_named(timeout, w1_timeout, int, 0);
+module_param_named(scan_interval, w1_scan_interval, int, 0);
module_param_named(max_slave_count, w1_max_slave_count, int, 0);
module_param_named(slave_ttl, w1_max_slave_ttl, int, 0);

@@ -357,7 +357,7 @@ static int w1_process(void *data)

while (!dev->need_exit) {
try_to_freeze(PF_FREEZE);
- msleep_interruptible(w1_timeout * 1000);
+ msleep_interruptible(dev->scan_interval * 1000);

if (signal_pending(current))
flush_signals(current);
@@ -401,33 +401,71 @@ static ssize_t w1_master_attribute_show_
return sprintf(buf, "%s\n", master->name);
}

-static ssize_t w1_master_attribute_show_timeout(struct device *dev, char *buf)
+static ssize_t
+w1_master_attribute_show_scan_interval(struct device *dev, char *buf)
{
- ssize_t count;
- count = sprintf(buf, "%d\n", w1_timeout);
- return count;
+ struct w1_master *master = to_w1_master(dev);
+
+ return sprintf(buf, "%d\n", master->scan_interval);
+}
+
+static ssize_t
+w1_master_attribute_set_scan_interval(struct device *dev, const char *buf,
+ size_t n)
+{
+ struct w1_master *master = to_w1_master(dev);
+ int interval;
+
+ interval = simple_strtoul(buf, NULL, 10);
+ if (!interval)
+ return -EINVAL;
+
+ master->scan_interval = interval;
+ return 0;
}

-static ssize_t w1_master_attribute_show_max_slave_count(struct device *dev, char *buf)
+static ssize_t
+w1_master_attribute_show_max_slave_count(struct device *dev, char *buf)
{
struct w1_master *master = to_w1_master(dev);

return sprintf(buf, "%d\n", master->max_slave_count);
}

+static ssize_t
+w1_master_attribute_set_max_slave_count(struct device *dev, const char *buf,
+ size_t n)
+{
+ struct w1_master *master = to_w1_master(dev);
+ int max_count;
+
+ max_count = simple_strtoul(buf, NULL, 10);
+ if (!max_count)
+ return -EINVAL;
+
+ master->max_slave_count = max_count;
+ return 0;
+}
+
#define W1_MASTER_ATTR_RO(_name, _mode) \
struct device_attribute w1_master_attribute_##_name = \
__ATTR(_name, _mode, \
w1_master_attribute_show_##_name, NULL)

+#define W1_MASTER_ATTR_RW(_name, _mode) \
+ struct device_attribute w1_master_attribute_##_name = \
+ __ATTR(_name, _mode, \
+ w1_master_attribute_show_##_name, \
+ w1_master_attribute_set_##_name)
+
static W1_MASTER_ATTR_RO(name, S_IRUGO);
-static W1_MASTER_ATTR_RO(max_slave_count, S_IRUGO);
-static W1_MASTER_ATTR_RO(timeout, S_IRUGO);
+static W1_MASTER_ATTR_RW(max_slave_count, S_IWUSR | S_IRUGO);
+static W1_MASTER_ATTR_RW(scan_interval, S_IWUSR | S_IRUGO);

static struct attribute *w1_master_default_attrs[] = {
&w1_master_attribute_name.attr,
&w1_master_attribute_max_slave_count.attr,
- &w1_master_attribute_timeout.attr,
+ &w1_master_attribute_scan_interval.attr,
NULL
};

Index: dtor/drivers/w1/w1.h
===================================================================
--- dtor.orig/drivers/w1/w1.h
+++ dtor/drivers/w1/w1.h
@@ -107,6 +107,7 @@ struct w1_master
struct list_head slist;
int max_slave_count;
int slave_ttl;
+ int scan_interval;
int initialized;
u32 id;

2005-04-21 08:25:57

by Dmitry Torokhov

[permalink] [raw]
Subject: [RFC/PATCH 18/22] W1: cleanup family implementation

W1: clean-up family implementation:
- get rid of w1_family_ops and template attributes in w1_slave
structure and have family drivers create necessary attributes
themselves. There are too many different devices using 1-Wire
interface and it is impossible to fit them all into single
attribute model. If interface unification is needed it can be
done by building cross-bus class hierarchy.
- rename w1_smem to w1_sernum because devices are called Silicon
serial numbers, they have address (ID) but don't have memory
in regular sense.
- rename w1_therm to w1_thermal.

Signed-off-by: Dmitry Torokhov <[email protected]>
---

drivers/w1/w1_smem.c | 103 -----------------------
drivers/w1/w1_therm.c | 188 -------------------------------------------
dtor/drivers/w1/Kconfig | 13 +-
dtor/drivers/w1/Makefile | 4
dtor/drivers/w1/w1.c | 148 +++++++++------------------------
dtor/drivers/w1/w1.h | 5 -
dtor/drivers/w1/w1_family.c | 37 +++++---
dtor/drivers/w1/w1_family.h | 23 +----
dtor/drivers/w1/w1_sernum.c | 58 +++++++++++++
dtor/drivers/w1/w1_thermal.c | 173 +++++++++++++++++++++++++++++++++++++++
10 files changed, 317 insertions(+), 435 deletions(-)

Index: dtor/drivers/w1/w1_therm.c
===================================================================
--- dtor.orig/drivers/w1/w1_therm.c
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * w1_therm.c
- *
- * Copyright (c) 2004 Evgeniy Polyakov <[email protected]>
- *
- *
- * 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 <linux/delay.h>
-
-#include "w1.h"
-#include "w1_io.h"
-#include "w1_family.h"
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Evgeniy Polyakov <[email protected]>");
-MODULE_DESCRIPTION("Driver for 1-wire Dallas network protocol, temperature family.");
-
-static u8 bad_roms[][9] = {
- {0xaa, 0x00, 0x4b, 0x46, 0xff, 0xff, 0x0c, 0x10, 0x87},
- {}
- };
-
-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 = {
- .rbin = &w1_therm_read_bin,
- .rval = &w1_therm_read_temp,
- .rvalname = "temp1_input",
-};
-
-static inline int w1_convert_temp(u8 rom[9])
-{
- int t, h;
-
- if (rom[1] == 0)
- t = ((s32)rom[0] >> 1)*1000;
- else
- t = 1000*(-1*(s32)(0x100-rom[0]) >> 1);
-
- t -= 250;
- h = 1000*((s32)rom[7] - (s32)rom[6]);
- h /= (s32)rom[7];
- t += h;
-
- return t;
-}
-
-static ssize_t w1_therm_read_temp(struct device *dev, char *buf)
-{
- struct w1_slave *sl = container_of(dev, struct w1_slave, dev);
-
- return sprintf(buf, "%d\n", w1_convert_temp(sl->rom));
-}
-
-static int w1_therm_check_rom(u8 rom[9])
-{
- int i;
-
- for (i=0; i<sizeof(bad_roms)/9; ++i)
- if (!memcmp(bad_roms[i], rom, 9))
- return 1;
-
- return 0;
-}
-
-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;
- int i, max_trying = 10;
-
- if (down_interruptible(&sl->master->mutex))
- return 0;
-
- if (off > W1_SLAVE_DATA_SIZE) {
- count = 0;
- goto out;
- }
- if (off + count > W1_SLAVE_DATA_SIZE) {
- count = 0;
- goto out;
- }
-
- memset(buf, 0, count);
- memset(rom, 0, sizeof(rom));
-
- count = 0;
- verdict = 0;
- crc = 0;
-
- while (max_trying--) {
- if (!w1_reset_bus (dev)) {
- int count = 0;
- u8 match[9] = {W1_MATCH_ROM, };
- unsigned int tm = 750;
-
- memcpy(&match[1], (u64 *) & sl->reg_num, 8);
-
- w1_write_block(dev, match, 9);
-
- w1_write_8(dev, W1_CONVERT_TEMP);
-
- while (tm) {
- tm = msleep_interruptible(tm);
- if (signal_pending(current))
- flush_signals(current);
- }
-
- if (!w1_reset_bus (dev)) {
- w1_write_block(dev, match, 9);
-
- w1_write_8(dev, W1_READ_SCRATCHPAD);
- if ((count = w1_read_block(dev, rom, 9)) != 9) {
- dev_warn(&dev->dev, "w1_read_block() returned %d instead of 9.\n", count);
- }
-
- crc = w1_calc_crc8(rom, 8);
-
- if (rom[8] == crc && rom[0])
- verdict = 1;
-
- }
- }
-
- if (!w1_therm_check_rom(rom))
- break;
- }
-
- for (i = 0; i < 9; ++i)
- count += sprintf(buf + count, "%02x ", rom[i]);
- count += sprintf(buf + count, ": crc=%02x %s\n",
- crc, (verdict) ? "YES" : "NO");
- if (verdict)
- memcpy(sl->rom, rom, sizeof(sl->rom));
- else
- dev_warn(&dev->dev, "18S20 doesn't respond to CONVERT_TEMP.\n");
-
- for (i = 0; i < 9; ++i)
- count += sprintf(buf + count, "%02x ", sl->rom[i]);
-
- count += sprintf(buf + count, "t=%d\n", w1_convert_temp(rom));
-out:
- up(&dev->mutex);
-
- return count;
-}
-
-static struct w1_family w1_therm_family = {
- .fid = W1_FAMILY_THERM,
- .fops = &w1_therm_fops,
-};
-
-static int __init w1_therm_init(void)
-{
- return w1_register_family(&w1_therm_family);
-}
-
-static void __exit w1_therm_fini(void)
-{
- w1_unregister_family(&w1_therm_family);
-}
-
-module_init(w1_therm_init);
-module_exit(w1_therm_fini);
Index: dtor/drivers/w1/w1_smem.c
===================================================================
--- dtor.orig/drivers/w1/w1_smem.c
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * w1_smem.c
- *
- * Copyright (c) 2004 Evgeniy Polyakov <[email protected]>
- *
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the smems 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_family.h"
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Evgeniy Polyakov <[email protected]>");
-MODULE_DESCRIPTION("Driver for 1-wire Dallas network protocol, 64bit memory family.");
-
-static ssize_t w1_smem_read_val(struct device *, char *);
-static ssize_t w1_smem_read_bin(struct kobject *, char *, loff_t, size_t);
-
-static struct w1_family_ops w1_smem_fops = {
- .rbin = &w1_smem_read_bin,
- .rval = &w1_smem_read_val,
- .rvalname = "id",
-};
-
-static ssize_t w1_smem_read_val(struct device *dev, char *buf)
-{
- struct w1_slave *sl = container_of(dev, struct w1_slave, dev);
- int i;
- ssize_t count = 0;
-
- for (i = 0; i < 9; ++i)
- count += sprintf(buf + count, "%02x ", ((u8 *)&sl->reg_num)[i]);
- count += sprintf(buf + count, "\n");
-
- return count;
-}
-
-static ssize_t w1_smem_read_bin(struct kobject *kobj, char *buf, loff_t off, size_t count)
-{
- struct w1_slave *sl = container_of(container_of(kobj, struct device, kobj),
- struct w1_slave, dev);
- int i;
-
- if (down_interruptible(&sl->master->mutex))
- return 0;
-
- if (off > W1_SLAVE_DATA_SIZE) {
- count = 0;
- goto out;
- }
- if (off + count > W1_SLAVE_DATA_SIZE) {
- count = 0;
- goto out;
- }
- for (i = 0; i < 9; ++i)
- count += sprintf(buf + count, "%02x ", ((u8 *)&sl->reg_num)[i]);
- count += sprintf(buf + count, "\n");
-
-out:
- up(&sl->master->mutex);
-
- return count;
-}
-
-static struct w1_family w1_smem_family = {
- .fid = W1_FAMILY_SMEM,
- .fops = &w1_smem_fops,
-};
-
-static int __init w1_smem_init(void)
-{
- return w1_register_family(&w1_smem_family);
-}
-
-static void __exit w1_smem_fini(void)
-{
- w1_unregister_family(&w1_smem_family);
-}
-
-module_init(w1_smem_init);
-module_exit(w1_smem_fini);
Index: dtor/drivers/w1/w1.c
===================================================================
--- dtor.orig/drivers/w1/w1.c
+++ dtor/drivers/w1/w1.c
@@ -2,6 +2,7 @@
* w1.c
*
* Copyright (c) 2004 Evgeniy Polyakov <[email protected]>
+ * Copyright (c) 2005 Dmitry Torokhov <[email protected]>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -97,30 +98,6 @@ static struct attribute_group w1_slave_d
.attrs = w1_slave_default_attrs,
};

-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");
-}
-
-static struct device_attribute w1_slave_attribute_val =
- __ATTR(value, S_IRUGO, w1_default_read_name, NULL);
-
-static struct bin_attribute w1_slave_bin_attribute = {
- .attr = {
- .name = "w1_slave",
- .mode = S_IRUGO,
- .owner = THIS_MODULE,
- },
- .size = W1_SLAVE_DATA_SIZE,
- .read = &w1_default_read_bin,
-};
-
static void w1_slave_release(struct device *dev)
{
struct w1_slave *slave = to_w1_slave(dev);
@@ -130,79 +107,10 @@ static void w1_slave_release(struct devi
module_put(THIS_MODULE);
}

-static int __w1_attach_slave_device(struct w1_slave *slave)
-{
- int err;
-
- slave->dev.parent = &slave->master->dev;
- slave->dev.bus = &w1_bus_type;
- slave->dev.release = &w1_slave_release;
-
- snprintf(&slave->dev.bus_id[0], sizeof(slave->dev.bus_id),
- "%02x-%012llx",
- (unsigned int) slave->reg_num.family,
- (unsigned long long) slave->reg_num.id);
-
- dev_dbg(&slave->dev, "%s: registering %s.\n", __func__,
- &slave->dev.bus_id[0]);
-
- err = device_register(&slave->dev);
- if (err < 0) {
- dev_err(&slave->dev,
- "Device registration [%s] failed. err=%d\n",
- slave->dev.bus_id, err);
- return err;
- }
-
- __module_get(THIS_MODULE);
-
- memcpy(&slave->attr_bin, &w1_slave_bin_attribute, sizeof(slave->attr_bin));
- memcpy(&slave->attr_val, &w1_slave_attribute_val, sizeof(slave->attr_val));
-
- slave->attr_bin.read = slave->family->fops->rbin;
- slave->attr_val.show = slave->family->fops->rval;
- slave->attr_val.attr.name = slave->family->fops->rvalname;
-
- err = device_create_file(&slave->dev, &slave->attr_val);
- if (err < 0) {
- dev_err(&slave->dev,
- "sysfs file creation for [%s] failed. err=%d\n",
- slave->dev.bus_id, err);
- device_unregister(&slave->dev);
- return err;
- }
-
- err = sysfs_create_bin_file(&slave->dev.kobj, &slave->attr_bin);
- if (err < 0) {
- dev_err(&slave->dev,
- "sysfs file creation for [%s] failed. err=%d\n",
- slave->dev.bus_id, err);
- device_remove_file(&slave->dev, &slave->attr_val);
- device_unregister(&slave->dev);
- return err;
- }
-
- err = sysfs_create_group(&slave->dev.kobj, &w1_slave_defattr_group);
- if (err < 0) {
- dev_err(&slave->dev,
- "sysfs group creation for [%s] failed. err=%d\n",
- slave->dev.bus_id, err);
- sysfs_remove_bin_file(&slave->dev.kobj, &slave->attr_bin);
- device_remove_file(&slave->dev, &slave->attr_val);
- device_unregister(&slave->dev);
- return err;
- }
-
- list_add_tail(&slave->node, &slave->master->slist);
-
- return 0;
-}
-
static int w1_attach_slave_device(struct w1_master *master, struct w1_reg_num *rn)
{
struct w1_slave *slave;
- struct w1_family *f;
- int err;
+ int error;

slave = kcalloc(1, sizeof(struct w1_slave), GFP_KERNEL);
if (!slave) {
@@ -212,13 +120,16 @@ static int w1_attach_slave_device(struct
return -ENOMEM;
}

+ init_MUTEX(&slave->mutex);
+ INIT_LIST_HEAD(&slave->node);
slave->master = master;
slave->reg_num = *rn;
set_bit(W1_SLAVE_ACTIVE, &slave->flags);
+ slave->ttl = master->slave_ttl;

spin_lock(&w1_flock);
- f = w1_family_registered(rn->family);
- if (!f) {
+ slave->family = w1_family_registered(rn->family);
+ if (!slave->family) {
spin_unlock(&w1_flock);
dev_info(&master->dev,
"Family %x for %02x.%012llx.%02x is not registered.\n",
@@ -227,21 +138,45 @@ static int w1_attach_slave_device(struct
kfree(slave);
return -ENODEV;
}
- __w1_family_get(f);
+ __w1_family_get(slave->family);
spin_unlock(&w1_flock);

- slave->family = f;
+ slave->dev.parent = &slave->master->dev;
+ slave->dev.bus = &w1_bus_type;
+ slave->dev.release = &w1_slave_release;
+
+ snprintf(&slave->dev.bus_id[0], sizeof(slave->dev.bus_id),
+ "%02x-%012llx",
+ (unsigned int) slave->reg_num.family,
+ (unsigned long long) slave->reg_num.id);
+
+ dev_dbg(&slave->dev, "%s: registering %s.\n", __func__,
+ &slave->dev.bus_id[0]);

- err = __w1_attach_slave_device(slave);
- if (err < 0) {
- dev_err(&master->dev, "%s: Attaching %s failed.\n", __func__,
- slave->dev.bus_id);
+ error = device_register(&slave->dev);
+ if (error < 0) {
+ dev_err(&slave->dev,
+ "Device registration [%s] failed. err=%d\n",
+ slave->dev.bus_id, error);
w1_family_put(slave->family);
kfree(slave);
- return err;
+ return error;
}

- slave->ttl = master->slave_ttl;
+ __module_get(THIS_MODULE);
+
+ error = sysfs_create_group(&slave->dev.kobj, &w1_slave_defattr_group);
+ if (error < 0) {
+ dev_err(&slave->dev,
+ "sysfs group creation for [%s] failed. err=%d\n",
+ slave->dev.bus_id, error);
+ device_unregister(&slave->dev);
+ return error;
+ }
+
+ w1_family_join(slave); /* assume it always succeeds for now */
+
+ list_add_tail(&slave->node, &slave->master->slist);

return 0;
}
@@ -251,9 +186,8 @@ static void w1_slave_detach(struct w1_sl
dev_info(&slave->dev, "%s: detaching %s.\n",
__func__, slave->dev.bus_id);

+ w1_family_leave(slave);
sysfs_remove_group(&slave->dev.kobj, &w1_slave_defattr_group);
- sysfs_remove_bin_file(&slave->dev.kobj, &slave->attr_bin);
- device_remove_file(&slave->dev, &slave->attr_val);
device_unregister(&slave->dev);
}

@@ -519,10 +453,12 @@ void w1_remove_master_device(struct w1_m

w1_stop_master_device(master);

+ down(&master->mutex);
list_for_each_entry_safe(slave, next, &master->slist, node) {
list_del(&slave->node);
w1_slave_detach(slave);
}
+ up(&master->mutex);

sysfs_remove_group(&master->dev.kobj, &w1_master_defattr_group);
device_unregister(&master->dev);
Index: dtor/drivers/w1/w1.h
===================================================================
--- dtor.orig/drivers/w1/w1.h
+++ dtor/drivers/w1/w1.h
@@ -47,7 +47,6 @@ struct w1_reg_num
#include "w1_family.h"

#define W1_MAXNAMELEN 32
-#define W1_SLAVE_DATA_SIZE 128

#define W1_SEARCH 0xF0
#define W1_CONDITIONAL_SEARCH 0xEC
@@ -71,9 +70,7 @@ struct w1_slave
struct w1_master *master;
struct w1_family *family;
struct device dev;
-
- struct bin_attribute attr_bin;
- struct device_attribute attr_name, attr_val;
+ struct semaphore mutex;
};
#define to_w1_slave(dev) container_of((dev), struct w1_slave, dev)

Index: dtor/drivers/w1/w1_thermal.c
===================================================================
--- /dev/null
+++ dtor/drivers/w1/w1_thermal.c
@@ -0,0 +1,173 @@
+/*
+ * w1_thermal.c
+ *
+ * Copyright (c) 2004 Evgeniy Polyakov <[email protected]>
+ * Copyright (c) 2005 Dmitry Torokhov <[email protected]>
+ *
+ *
+ * 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 <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+
+#include "w1.h"
+#include "w1_io.h"
+#include "w1_family.h"
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Evgeniy Polyakov <[email protected]>");
+MODULE_DESCRIPTION("1-Wire Digital Thermometer");
+
+static ssize_t w1_thermal_show_temp(struct device *, char *);
+
+static struct device_attribute w1_thermal_temperature_attr =
+ __ATTR(temp, S_IRUGO, w1_thermal_show_temp, NULL);
+
+static int w1_thermal_join(struct w1_slave *slave)
+{
+ return device_create_file(&slave->dev, &w1_thermal_temperature_attr);
+}
+
+static void w1_thermal_leave(struct w1_slave *slave)
+{
+ device_remove_file(&slave->dev, &w1_thermal_temperature_attr);
+}
+
+static struct w1_family w1_thermal_family = {
+ .fid = W1_FAMILY_THERMAL,
+ .join = w1_thermal_join,
+ .leave = w1_thermal_leave,
+};
+
+static u8 bad_roms[][9] = {
+ { 0xaa, 0x00, 0x4b, 0x46, 0xff, 0xff, 0x0c, 0x10, 0x87 },
+ { }
+};
+
+static inline int w1_convert_temp(u8 rom[9])
+{
+ int t, h;
+
+ if (rom[1] == 0)
+ t = ((s32)rom[0] >> 1) * 1000;
+ else
+ t = 1000 * (-1 * (s32)(0x100 - rom[0]) >> 1);
+
+ t -= 250;
+ h = 1000 * ((s32)rom[7] - (s32)rom[6]);
+ h /= (s32)rom[7];
+ t += h;
+
+ return t;
+}
+
+static int w1_therm_check_rom(u8 rom[9])
+{
+ int i;
+
+ for (i = 0; i < sizeof(bad_roms) / 9; i++)
+ if (!memcmp(bad_roms[i], rom, 9))
+ return 1;
+
+ return 0;
+}
+
+static int w1_thermal_read_data(struct w1_slave *slave, u8 data[])
+{
+ struct w1_master *dev = slave->master;
+ u8 match[9] = { W1_MATCH_ROM, };
+ u8 crc;
+ int count;
+ int error;
+
+ memset(data, 0, 9);
+
+ error = w1_reset_bus(dev);
+ if (error)
+ return error;
+
+ memcpy(&match[1], (u64 *)&slave->reg_num, sizeof(u64));
+
+ w1_write_block(dev, match, 9);
+ w1_write_8(dev, W1_CONVERT_TEMP);
+ msleep(750);
+
+ error = w1_reset_bus(dev);
+ if (error)
+ return error;
+
+ w1_write_block(dev, match, 9);
+ w1_write_8(dev, W1_READ_SCRATCHPAD);
+ if ((count = w1_read_block(dev, data, 9)) != 9)
+ dev_warn(&dev->dev, "w1_read_block() returned %d instead of 9.\n", count);
+
+ crc = w1_calc_crc8(data, 8);
+ if (data[8] != crc || !data[0] || w1_therm_check_rom(data))
+ return -EIO;
+
+ return 0;
+}
+
+static ssize_t w1_thermal_show_temp(struct device *dev, char *buf)
+{
+ struct w1_slave *slave = to_w1_slave(dev);
+ int attempts = 10;
+ u8 data[9];
+ int error;
+ ssize_t count = 0;
+
+ error = down_interruptible(&slave->master->mutex);
+ if (error)
+ return error;
+
+ error = down_interruptible(&slave->mutex);
+ if (error)
+ goto out;
+
+ if (slave->family != &w1_thermal_family) {
+ error = -ENODEV;
+ goto out;
+ }
+
+ do {
+ error = w1_thermal_read_data(slave, data);
+ if (!error)
+ count = sprintf(buf, "%d\n", w1_convert_temp(data));
+
+ } while (error && attempts-- > 0);
+
+ up(&slave->mutex);
+out:
+ up(&slave->master->mutex);
+ return error ? error : count;
+}
+
+static int __init w1_thermal_init(void)
+{
+ return w1_register_family(&w1_thermal_family);
+}
+
+static void __exit w1_thermal_exit(void)
+{
+ w1_unregister_family(&w1_thermal_family);
+}
+
+module_init(w1_thermal_init);
+module_exit(w1_thermal_exit);
Index: dtor/drivers/w1/Makefile
===================================================================
--- dtor.orig/drivers/w1/Makefile
+++ dtor/drivers/w1/Makefile
@@ -10,8 +10,8 @@ obj-$(CONFIG_W1) += wire.o
wire-objs := w1.o w1_family.o w1_io.o

obj-$(CONFIG_W1_MATROX) += matrox_w1.o
-obj-$(CONFIG_W1_THERM) += w1_therm.o
-obj-$(CONFIG_W1_SMEM) += w1_smem.o
+obj-$(CONFIG_W1_THERMAL) += w1_thermal.o
+obj-$(CONFIG_W1_SERNUM) += w1_sernum.o

obj-$(CONFIG_W1_DS9490) += ds9490r.o
ds9490r-objs := dscore.o
Index: dtor/drivers/w1/w1_sernum.c
===================================================================
--- /dev/null
+++ dtor/drivers/w1/w1_sernum.c
@@ -0,0 +1,58 @@
+/*
+ * w1_sernum.c
+ *
+ * Copyright (c) 2004 Evgeniy Polyakov <[email protected]>
+ * Copyright (c) 2005 Dmitry Torokhov <[email protected]>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the smems 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/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/types.h>
+
+#include "w1.h"
+#include "w1_family.h"
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Evgeniy Polyakov <[email protected]>");
+MODULE_DESCRIPTION("1-Wire Silicon Serial Number Driver");
+
+/*
+ * This is a very dumb device. It just has an unique ID and
+ * sits on the bus doing nothing. So the driver does not do
+ * anything fancy either; access to device's ID is provided
+ * by W1 core.
+ */
+
+static struct w1_family w1_serial_num_family = {
+ .fid = W1_FAMILY_SERIAL_NUM,
+};
+
+static int __init w1_serial_num_init(void)
+{
+ return w1_register_family(&w1_serial_num_family);
+}
+
+static void __exit w1_serial_num_exit(void)
+{
+ w1_unregister_family(&w1_serial_num_family);
+}
+
+module_init(w1_serial_num_init);
+module_exit(w1_serial_num_exit);
Index: dtor/drivers/w1/Kconfig
===================================================================
--- dtor.orig/drivers/w1/Kconfig
+++ dtor/drivers/w1/Kconfig
@@ -40,18 +40,19 @@ config W1_DS9490_BRIDGE
This support is also available as a module. If so, the module
will be called ds_w1_bridge.ko.

-config W1_THERM
- tristate "Thermal family implementation"
+config W1_THERMAL
+ tristate "Thermal sensor devices"
depends on W1
help
- Say Y here if you want to connect 1-wire thermal sensors to you
+ Say Y here if you want to connect 1-wire thermal sensors to your
wire.

-config W1_SMEM
- tristate "Simple 64bit memory family implementation"
+config W1_SERNUM
+ tristate "Silicon Serial Number devices"
depends on W1
help
Say Y here if you want to connect 1-wire
- simple 64bit memory rom(ds2401/ds2411/ds1990*) to you wire.
+ simple addressable devices (Silicon Serial Nnumbers -
+ ds2401/ds2411/ds1990*) to your wire.

endmenu
Index: dtor/drivers/w1/w1_family.c
===================================================================
--- dtor.orig/drivers/w1/w1_family.c
+++ dtor/drivers/w1/w1_family.c
@@ -23,28 +23,18 @@
#include <linux/list.h>
#include <linux/delay.h>

+#include "w1.h"
#include "w1_family.h"

DEFINE_SPINLOCK(w1_flock);
static LIST_HEAD(w1_families);

-static int w1_check_family(struct w1_family *f)
-{
- if (!f->fops->rbin || !f->fops->rval || !f->fops->rvalname)
- return -EINVAL;
-
- return 0;
-}
-
int w1_register_family(struct w1_family *newf)
{
struct list_head *ent, *n;
struct w1_family *f;
int ret = 0;

- if (w1_check_family(newf))
- return -EINVAL;
-
spin_lock(&w1_flock);
list_for_each_safe(ent, n, &w1_families) {
f = list_entry(ent, struct w1_family, family_entry);
@@ -115,6 +105,31 @@ struct w1_family * w1_family_registered(
return (ret) ? f : NULL;
}

+int w1_family_join(struct w1_slave *slave)
+{
+ int retval;
+
+ retval = down_interruptible(&slave->mutex);
+ if (retval)
+ return retval;
+
+ if (slave->family->join)
+ retval = slave->family->join(slave);
+
+ up(&slave->mutex);
+ return retval;
+}
+
+void w1_family_leave(struct w1_slave *slave)
+{
+ down(&slave->mutex);
+
+ if (slave->family->leave)
+ slave->family->leave(slave);
+
+ up(&slave->mutex);
+}
+
void w1_family_put(struct w1_family *f)
{
spin_lock(&w1_flock);
Index: dtor/drivers/w1/w1_family.h
===================================================================
--- dtor.orig/drivers/w1/w1_family.h
+++ dtor/drivers/w1/w1_family.h
@@ -26,28 +26,20 @@
#include <linux/device.h>
#include <asm/atomic.h>

-#define W1_FAMILY_DEFAULT 0
-#define W1_FAMILY_THERM 0x10
-#define W1_FAMILY_SMEM 0x01
+#define W1_FAMILY_SERIAL_NUM 0x01
+#define W1_FAMILY_THERMAL 0x10

-#define MAXNAMELEN 32
-
-struct w1_family_ops
-{
- ssize_t (* rbin)(struct kobject *, char *, loff_t, size_t);
- ssize_t (* rval)(struct device *, char *);
- unsigned char rvalname[MAXNAMELEN];
-};
+struct w1_slave;

struct w1_family
{
struct list_head family_entry;
u8 fid;
-
- struct w1_family_ops *fops;
-
atomic_t refcnt;
u8 need_exit;
+
+ int (*join)(struct w1_slave *);
+ void (*leave)(struct w1_slave *);
};

extern spinlock_t w1_flock;
@@ -57,7 +49,8 @@ void w1_family_put(struct w1_family *);
void __w1_family_get(struct w1_family *);
void __w1_family_put(struct w1_family *);
struct w1_family * w1_family_registered(u8);
+int w1_family_join(struct w1_slave *);
+void w1_family_leave(struct w1_slave *);
void w1_unregister_family(struct w1_family *);
int w1_register_family(struct w1_family *);
-
#endif /* __W1_FAMILY_H */

2005-04-21 08:28:31

by Dmitry Torokhov

[permalink] [raw]
Subject: [RFC/PATCH 19/22] W1: convert families to be proper sysfs rivers

W1: convert family into proper device-model drivers:
- embed driver structure into w1_family and register with the
driver core;
- do not try to manually bind slaves to familes, leave it to
the driver core;
- fold w1_family.c into w1.c

Signed-off-by: Dmitry Torokhov <[email protected]>
---

drivers/w1/w1_family.c | 165 -------------------------------------------
dtor/drivers/w1/Makefile | 2
dtor/drivers/w1/w1.c | 118 +++++++++++++++++++++++-------
dtor/drivers/w1/w1.h | 16 +++-
dtor/drivers/w1/w1_family.h | 28 -------
dtor/drivers/w1/w1_sernum.c | 4 +
dtor/drivers/w1/w1_thermal.c | 6 +
7 files changed, 114 insertions(+), 225 deletions(-)

Index: dtor/drivers/w1/w1.c
===================================================================
--- dtor.orig/drivers/w1/w1.c
+++ dtor/drivers/w1/w1.c
@@ -37,7 +37,6 @@
#include "w1.h"
#include "w1_io.h"
#include "w1_log.h"
-#include "w1_family.h"

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Evgeniy Polyakov <[email protected]>");
@@ -51,14 +50,24 @@ module_param_named(scan_interval, w1_sca
module_param_named(max_slave_count, w1_max_slave_count, int, 0);
module_param_named(slave_ttl, w1_max_slave_ttl, int, 0);

-static int w1_master_match(struct device *dev, struct device_driver *drv)
+static int w1_bus_match(struct device *dev, struct device_driver *drv)
{
- return 1;
+ /*
+ * Master devices are bound explicitely upon registration
+ * so we can only get slaves here.
+ */
+ struct w1_slave *slave = to_w1_slave(dev);
+ struct w1_family *family = to_w1_family(drv);
+
+ if (slave->reg_num.family == family->fid)
+ return 1;
+
+ return 0;
}

static struct bus_type w1_bus_type = {
.name = "w1",
- .match = w1_master_match,
+ .match = w1_bus_match,
};

struct device_driver w1_master_driver = {
@@ -102,7 +111,6 @@ static void w1_slave_release(struct devi
{
struct w1_slave *slave = to_w1_slave(dev);

- w1_family_put(slave->family);
kfree(slave);
module_put(THIS_MODULE);
}
@@ -127,28 +135,13 @@ static int w1_attach_slave_device(struct
set_bit(W1_SLAVE_ACTIVE, &slave->flags);
slave->ttl = master->slave_ttl;

- spin_lock(&w1_flock);
- slave->family = w1_family_registered(rn->family);
- if (!slave->family) {
- spin_unlock(&w1_flock);
- dev_info(&master->dev,
- "Family %x for %02x.%012llx.%02x is not registered.\n",
- rn->family, rn->family,
- (unsigned long long)rn->id, rn->crc);
- kfree(slave);
- return -ENODEV;
- }
- __w1_family_get(slave->family);
- spin_unlock(&w1_flock);
-
- slave->dev.parent = &slave->master->dev;
- slave->dev.bus = &w1_bus_type;
- slave->dev.release = &w1_slave_release;
-
snprintf(&slave->dev.bus_id[0], sizeof(slave->dev.bus_id),
"%02x-%012llx",
(unsigned int) slave->reg_num.family,
(unsigned long long) slave->reg_num.id);
+ slave->dev.parent = &slave->master->dev;
+ slave->dev.bus = &w1_bus_type;
+ slave->dev.release = &w1_slave_release;

dev_dbg(&slave->dev, "%s: registering %s.\n", __func__,
&slave->dev.bus_id[0]);
@@ -158,7 +151,6 @@ static int w1_attach_slave_device(struct
dev_err(&slave->dev,
"Device registration [%s] failed. err=%d\n",
slave->dev.bus_id, error);
- w1_family_put(slave->family);
kfree(slave);
return error;
}
@@ -174,8 +166,6 @@ static int w1_attach_slave_device(struct
return error;
}

- w1_family_join(slave); /* assume it always succeeds for now */
-
list_add_tail(&slave->node, &slave->master->slist);

return 0;
@@ -186,7 +176,6 @@ static void w1_slave_detach(struct w1_sl
dev_info(&slave->dev, "%s: detaching %s.\n",
__func__, slave->dev.bus_id);

- w1_family_leave(slave);
sysfs_remove_group(&slave->dev.kobj, &w1_slave_defattr_group);
device_unregister(&slave->dev);
}
@@ -464,6 +453,79 @@ void w1_remove_master_device(struct w1_m
device_unregister(&master->dev);
}

+static int w1_family_probe(struct device *dev)
+{
+ struct w1_slave *slave = to_w1_slave(dev);
+ struct w1_family *family = to_w1_family(dev->driver);
+ int retval;
+
+ retval = down_interruptible(&slave->mutex);
+ if (retval)
+ return retval;
+
+ if (family->join)
+ retval = family->join(slave);
+
+ up(&slave->mutex);
+ return retval;
+}
+
+static int w1_family_remove(struct device *dev)
+{
+ struct w1_slave *slave = to_w1_slave(dev);
+ struct w1_family *family = to_w1_family(dev->driver);
+
+ down(&slave->mutex);
+
+ if (family->leave)
+ family->leave(slave);
+
+ up(&slave->mutex);
+ return 0;
+}
+
+static ssize_t w1_family_show_name(struct device_driver *drv, char *buf)
+{
+ struct w1_family *family = to_w1_family(drv);
+
+ return sprintf(buf, "%s\n", family->name);
+}
+
+static struct driver_attribute w1_family_attribute_name =
+ __ATTR(name, S_IRUGO, w1_family_show_name, NULL);
+
+int w1_register_family(struct w1_family *family)
+{
+ int error;
+
+ family->driver.bus = &w1_bus_type;
+ family->driver.probe = w1_family_probe;
+ family->driver.remove = w1_family_remove;
+
+ error = driver_register(&family->driver);
+ if (error) {
+ printk(KERN_ERR "w1: Failed to register family. err=%d.\n",
+ error);
+ return error;
+ }
+
+ error = driver_create_file(&family->driver, &w1_family_attribute_name);
+ if (error) {
+ printk(KERN_ERR
+ "w1: Failed to create name family attribute. err=%d.\n",
+ error);
+ driver_unregister(&family->driver);
+ return error;
+ }
+
+ return 0;
+}
+
+void w1_unregister_family(struct w1_family *family)
+{
+ driver_unregister(&family->driver);
+}
+
static int w1_init(void)
{
int error;
@@ -501,3 +563,5 @@ module_exit(w1_exit);
EXPORT_SYMBOL(w1_allocate_master_device);
EXPORT_SYMBOL(w1_add_master_device);
EXPORT_SYMBOL(w1_remove_master_device);
+EXPORT_SYMBOL(w1_register_family);
+EXPORT_SYMBOL(w1_unregister_family);
Index: dtor/drivers/w1/w1.h
===================================================================
--- dtor.orig/drivers/w1/w1.h
+++ dtor/drivers/w1/w1.h
@@ -44,8 +44,6 @@ struct w1_reg_num

#include <asm/semaphore.h>

-#include "w1_family.h"
-
#define W1_MAXNAMELEN 32

#define W1_SEARCH 0xF0
@@ -68,7 +66,6 @@ struct w1_slave
int ttl;

struct w1_master *master;
- struct w1_family *family;
struct device dev;
struct semaphore mutex;
};
@@ -119,6 +116,19 @@ struct w1_master *w1_allocate_master_dev
int w1_add_master_device(struct w1_master *);
void w1_remove_master_device(struct w1_master *);

+struct w1_family {
+ struct device_driver driver;
+ u8 fid;
+ const char *name;
+
+ int (*join)(struct w1_slave *);
+ void (*leave)(struct w1_slave *);
+};
+#define to_w1_family(drv) container_of((drv), struct w1_family, driver)
+
+int w1_register_family(struct w1_family *f);
+void w1_unregister_family(struct w1_family *f);
+
#endif /* __KERNEL__ */

#endif /* __W1_H */
Index: dtor/drivers/w1/w1_thermal.c
===================================================================
--- dtor.orig/drivers/w1/w1_thermal.c
+++ dtor/drivers/w1/w1_thermal.c
@@ -51,7 +51,11 @@ static void w1_thermal_leave(struct w1_s
}

static struct w1_family w1_thermal_family = {
+ .driver = {
+ .name = "thermal",
+ },
.fid = W1_FAMILY_THERMAL,
+ .name = "Digital Thermometer Driver",
.join = w1_thermal_join,
.leave = w1_thermal_leave,
};
@@ -141,7 +145,7 @@ static ssize_t w1_thermal_show_temp(stru
if (error)
goto out;

- if (slave->family != &w1_thermal_family) {
+ if (slave->dev.driver != &w1_thermal_family.driver) {
error = -ENODEV;
goto out;
}
Index: dtor/drivers/w1/Makefile
===================================================================
--- dtor.orig/drivers/w1/Makefile
+++ dtor/drivers/w1/Makefile
@@ -7,7 +7,7 @@ EXTRA_CFLAGS += -DNETLINK_DISABLED
endif

obj-$(CONFIG_W1) += wire.o
-wire-objs := w1.o w1_family.o w1_io.o
+wire-objs := w1.o w1_io.o

obj-$(CONFIG_W1_MATROX) += matrox_w1.o
obj-$(CONFIG_W1_THERMAL) += w1_thermal.o
Index: dtor/drivers/w1/w1_sernum.c
===================================================================
--- dtor.orig/drivers/w1/w1_sernum.c
+++ dtor/drivers/w1/w1_sernum.c
@@ -41,7 +41,11 @@ MODULE_DESCRIPTION("1-Wire Silicon Seria
*/

static struct w1_family w1_serial_num_family = {
+ .driver = {
+ .name = "sernum",
+ },
.fid = W1_FAMILY_SERIAL_NUM,
+ .name = "Serial Number Driver",
};

static int __init w1_serial_num_init(void)
Index: dtor/drivers/w1/w1_family.h
===================================================================
--- dtor.orig/drivers/w1/w1_family.h
+++ dtor/drivers/w1/w1_family.h
@@ -22,35 +22,7 @@
#ifndef __W1_FAMILY_H
#define __W1_FAMILY_H

-#include <linux/types.h>
-#include <linux/device.h>
-#include <asm/atomic.h>
-
#define W1_FAMILY_SERIAL_NUM 0x01
#define W1_FAMILY_THERMAL 0x10

-struct w1_slave;
-
-struct w1_family
-{
- struct list_head family_entry;
- u8 fid;
- atomic_t refcnt;
- u8 need_exit;
-
- int (*join)(struct w1_slave *);
- void (*leave)(struct w1_slave *);
-};
-
-extern spinlock_t w1_flock;
-
-void w1_family_get(struct w1_family *);
-void w1_family_put(struct w1_family *);
-void __w1_family_get(struct w1_family *);
-void __w1_family_put(struct w1_family *);
-struct w1_family * w1_family_registered(u8);
-int w1_family_join(struct w1_slave *);
-void w1_family_leave(struct w1_slave *);
-void w1_unregister_family(struct w1_family *);
-int w1_register_family(struct w1_family *);
#endif /* __W1_FAMILY_H */
Index: dtor/drivers/w1/w1_family.c
===================================================================
--- dtor.orig/drivers/w1/w1_family.c
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * w1_family.c
- *
- * Copyright (c) 2004 Evgeniy Polyakov <[email protected]>
- *
- *
- * 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 <linux/delay.h>
-
-#include "w1.h"
-#include "w1_family.h"
-
-DEFINE_SPINLOCK(w1_flock);
-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(&w1_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(&w1_flock);
-
- return ret;
-}
-
-void w1_unregister_family(struct w1_family *fent)
-{
- struct list_head *ent, *n;
- struct w1_family *f;
-
- spin_lock(&w1_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(&w1_flock);
-
- while (atomic_read(&fent->refcnt)) {
- printk(KERN_INFO "Waiting for family %u to become free: refcnt=%d.\n",
- fent->fid, atomic_read(&fent->refcnt));
-
- if (msleep_interruptible(1000))
- flush_signals(current);
- }
-}
-
-/*
- * Should be called under w1_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;
-}
-
-int w1_family_join(struct w1_slave *slave)
-{
- int retval;
-
- retval = down_interruptible(&slave->mutex);
- if (retval)
- return retval;
-
- if (slave->family->join)
- retval = slave->family->join(slave);
-
- up(&slave->mutex);
- return retval;
-}
-
-void w1_family_leave(struct w1_slave *slave)
-{
- down(&slave->mutex);
-
- if (slave->family->leave)
- slave->family->leave(slave);
-
- up(&slave->mutex);
-}
-
-void w1_family_put(struct w1_family *f)
-{
- spin_lock(&w1_flock);
- __w1_family_put(f);
- spin_unlock(&w1_flock);
-}
-
-void __w1_family_put(struct w1_family *f)
-{
- if (atomic_dec_and_test(&f->refcnt))
- f->need_exit = 1;
-}
-
-void w1_family_get(struct w1_family *f)
-{
- spin_lock(&w1_flock);
- __w1_family_get(f);
- spin_unlock(&w1_flock);
-
-}
-
-void __w1_family_get(struct w1_family *f)
-{
- smp_mb__before_atomic_inc();
- atomic_inc(&f->refcnt);
- smp_mb__after_atomic_inc();
-}
-
-EXPORT_SYMBOL(w1_family_get);
-EXPORT_SYMBOL(w1_family_put);
-EXPORT_SYMBOL(w1_family_registered);
-EXPORT_SYMBOL(w1_unregister_family);
-EXPORT_SYMBOL(w1_register_family);

2005-04-21 08:39:01

by Dmitry Torokhov

[permalink] [raw]
Subject: [RFC/PATCH 21/22] W1: implement standard hotplug handler

Ahem.. Kmail just refuses send this on inline... Sorry.

--
Dmitry


Attachments:
(No filename) (67.00 B)
w1-hotplug.patch (2.15 kB)
Download all attachments

2005-04-21 08:51:23

by Dmitry Torokhov

[permalink] [raw]
Subject: [RFC/PATCH 20/22] W1: add w1_device_id/MODULE_DEVICE_TABLE for automatic driver loading

W1: support for automatic family drivers loading via hotplug:
- allow family drivers support list of families;
- export supported families through MODULE_DEVICE_TABLE.

Signed-off-by: Dmitry Torokhov <[email protected]>
---

drivers/w1/w1.c | 6 ++++--
drivers/w1/w1.h | 3 ++-
drivers/w1/w1_sernum.c | 9 ++++++++-
drivers/w1/w1_thermal.c | 9 ++++++++-
include/linux/mod_devicetable.h | 4 ++++
scripts/mod/file2alias.c | 16 ++++++++++++++++
6 files changed, 42 insertions(+), 5 deletions(-)

Index: dtor/drivers/w1/w1.c
===================================================================
--- dtor.orig/drivers/w1/w1.c
+++ dtor/drivers/w1/w1.c
@@ -58,9 +58,11 @@ static int w1_bus_match(struct device *d
*/
struct w1_slave *slave = to_w1_slave(dev);
struct w1_family *family = to_w1_family(drv);
+ struct w1_device_id *id;

- if (slave->reg_num.family == family->fid)
- return 1;
+ for (id = family->id_table; id->family; id++)
+ if (slave->reg_num.family == id->family)
+ return 1;

return 0;
}
Index: dtor/drivers/w1/w1.h
===================================================================
--- dtor.orig/drivers/w1/w1.h
+++ dtor/drivers/w1/w1.h
@@ -41,6 +41,7 @@ struct w1_reg_num

#include <linux/completion.h>
#include <linux/device.h>
+#include <linux/mod_devicetable.h>

#include <asm/semaphore.h>

@@ -118,7 +119,7 @@ void w1_remove_master_device(struct w1_m

struct w1_family {
struct device_driver driver;
- u8 fid;
+ struct w1_device_id *id_table;
const char *name;

int (*join)(struct w1_slave *);
Index: dtor/drivers/w1/w1_thermal.c
===================================================================
--- dtor.orig/drivers/w1/w1_thermal.c
+++ dtor/drivers/w1/w1_thermal.c
@@ -50,11 +50,18 @@ static void w1_thermal_leave(struct w1_s
device_remove_file(&slave->dev, &w1_thermal_temperature_attr);
}

+static struct w1_device_id w1_thermal_ids[] = {
+ { .family = W1_FAMILY_THERMAL, },
+ { }
+};
+
+MODULE_DEVICE_TABLE(w1, w1_thermal_ids);
+
static struct w1_family w1_thermal_family = {
.driver = {
.name = "thermal",
},
- .fid = W1_FAMILY_THERMAL,
+ .id_table = w1_thermal_ids,
.name = "Digital Thermometer Driver",
.join = w1_thermal_join,
.leave = w1_thermal_leave,
Index: dtor/drivers/w1/w1_sernum.c
===================================================================
--- dtor.orig/drivers/w1/w1_sernum.c
+++ dtor/drivers/w1/w1_sernum.c
@@ -40,11 +40,18 @@ MODULE_DESCRIPTION("1-Wire Silicon Seria
* by W1 core.
*/

+static struct w1_device_id w1_serial_num_ids[] = {
+ { .family = W1_FAMILY_SERIAL_NUM, },
+ { }
+};
+
+MODULE_DEVICE_TABLE(w1, w1_serial_num_ids);
+
static struct w1_family w1_serial_num_family = {
.driver = {
.name = "sernum",
},
- .fid = W1_FAMILY_SERIAL_NUM,
+ .id_table = w1_serial_num_ids,
.name = "Serial Number Driver",
};

Index: dtor/scripts/mod/file2alias.c
===================================================================
--- dtor.orig/scripts/mod/file2alias.c
+++ dtor/scripts/mod/file2alias.c
@@ -25,6 +25,7 @@ typedef Elf64_Addr kernel_ulong_t;
#include <stdint.h>
#endif

+typedef uint64_t __u64;
typedef uint32_t __u32;
typedef uint16_t __u16;
typedef unsigned char __u8;
@@ -199,6 +200,18 @@ static int do_serio_entry(const char *fi
return 1;
}

+/* Looks like: "w1:fidNsnN" */
+static int do_w1_entry(const char *filename,
+ struct w1_device_id *id, char *alias)
+{
+ id->family = TO_NATIVE(id->family);
+ id->serial = TO_NATIVE(id->serial);
+
+ sprintf(alias, "w1:fid%02Xsn%024llX", id->family, id->serial);
+
+ return 1;
+}
+
/* looks like: "pnp:dD" */
static int do_pnp_entry(const char *filename,
struct pnp_device_id *id, char *alias)
@@ -291,6 +304,9 @@ void handle_moddevtable(struct module *m
else if (sym_is(symname, "__mod_serio_device_table"))
do_table(symval, sym->st_size, sizeof(struct serio_device_id),
do_serio_entry, mod);
+ else if (sym_is(symname, "__mod_w1_device_table"))
+ do_table(symval, sym->st_size, sizeof(struct w1_device_id),
+ do_w1_entry, mod);
else if (sym_is(symname, "__mod_pnp_device_table"))
do_table(symval, sym->st_size, sizeof(struct pnp_device_id),
do_pnp_entry, mod);
Index: dtor/include/linux/mod_devicetable.h
===================================================================
--- dtor.orig/include/linux/mod_devicetable.h
+++ dtor/include/linux/mod_devicetable.h
@@ -174,5 +174,9 @@ struct serio_device_id {
__u8 proto;
};

+struct w1_device_id {
+ __u8 family;
+ __u64 serial;
+};

#endif /* LINUX_MOD_DEVICETABLE_H */

2005-04-21 13:12:45

by Evgeniy Polyakov

[permalink] [raw]
Subject: Re: [RFC/PATCH 0/22] W1: sysfs, lifetime and other fixes

On Thu, 2005-04-21 at 02:07 -0500, Dmitry Torokhov wrote:
> Hi,

Hello, Dmitry.

> I happened to take a look into drivers/w1 and found there bunch of thigs
> that IMO should be changed:
>
> - custom-made refcounting is racy

Why do you think so?
Did you find exactly the place which races against something?

> - lifetime rules need to be better enforced

Hmm, I misunderstand you.

> - family framework is insufficient for many advanced w1 devices

No, family framework is just indication which family is used.
Feel free to implement additional methods for various devices
and store them in driver's private areas like ipaq does.

> - custom-made hotplug notification over netlink should be removed in favor
> of standard hotplug notification

It is not hotplug, and your changes broke it completely.
I'm waiting for connector to be included or discarded, so I can move
w1 on top of it's interface or move connector's bits into the w1
subsystem.

> - sysfs attributes have unnecessary prefixes (like w1_master) or not needed
> at all (w1_master_pointer)

Yep, some of them can be suspicious from the first point of view.

> Please consider series of patches below. Unfortunately I do not have any W1
> equipment so it was only compile-tested. Please also note that lifetime and
> locking rules were changed on object-by-object base so mid-series some stuff
> may appear broken but as far as I can see the end result shoudl work pretty
> well.


I can test your changes next week, but I already have too many
objections
to apply the whole patch set.

> w1-whitespace.patch
> Whitespace fixes.
>
> w1-formatting.patch
> Some formatting changes to bring the code in line with CodingStyle
> guidelines.

Both above look ok, although they will not apply after patches
already sent to Greg but not yet in the tree are applied.

> w1-master-attr-group.patch
> Use attribute_group to create master device attributes to guarantee
> proper cleanup in case of failure. Also, hide most of attribute define
> ugliness in macros.

Yep, I like it.

> w1-slave-attr-group.patc
> Add 2 default attributes "family" and "serial" to slave devices, every
> 1-Wire slave has them. Use attribute_group to handle. The rest of slave
> attributes are left as is - will be dealt with later.

Serial number is already there in bus_id, family is there too.
Why do you need separate files?

> w1-lists-cleanup.patch
> List handling cleanup. Most of the list_for_each_safe users don't need
> *_safe variant, *_entry variant is better suited in most places. Also,
> checking retrieved list element for null is a bit pointless...

Yep, it is correct.

> w1-drop-owner.patch
> Drop owner field from w1_master and w1_slave structures. Just having it
> there does not magically fixes lifetime rules.

They do not even pretend, I still do not understand what is "lifetime
rules"?

> w1-bus-ops.patch
> Cleanup bus operations code:
> - have bus operatiions accept w1_master instead of unsigned long and
> drop data field from w1_bus_master so the structure can be statically
> allocated by driver implementing it;
> - rename w1_bus_master to w1_bus_ops to avoid confusion with w1_master;
> - separate master registering and allocation so drivers can setup proper
> link between private data and master and set useable master's name.

I strongly object against such changes.
1. w1 was designed in the way that w1 bus master drivers do not
know about other w1 world. It is very simple and very low-level
abstraction,
that only understands how to do low-level functions. It is not needed
do know about w1_master structure and even about it's existence.
2. All renaming are superfluous, I'm not against it, but completely do
not
understand it's merits.
3. You broke netlink allocation routing - it may fail and it is not
fatal.

> w1-fold-w1-int.patch
> Fold w1_int.c into w1.c - there is no point in artificially separating
> code for master devices between 2 files.

w1_int.c was created to store external interface implementation,
why do you want to move it into w1 core code?
It will only soil the code...

> w1-drop-netlink.patch
> Drop custom-made hotplug over netlink notification from w1 core.
> Standard hotplug mechanism should work just fine (patch will follow).

netlink notification was not created for hotplug.
Also I'm against w1 hotplug support, since hotplug is quite rarely used
in embedded platforms where the majority of w1 devices live.
I mean not to completely forget this idea,
but implement it in the way it will not hurt existing model.

> w1-drop-control-thread.patch
> Drop control thread from w1 core, whatever it does can also be done in
> the context of w1_remove_master_device. Also, pin the module when
> registering new master device to make sure that w1 core is not unloaded
> until last device is gone. This simplifies logic a lot.

Why do you think master can be removed in safe context only?
I have feature requests for both adding/removing and exporting
master devices and slaves to the external world.
Control thread is also the place in which we kick all devices
when we need it, but not only when we need to remove w1 core module.

> w1-move-search-to-io.patch
> Move w1_search function to w1_io.c to be with the rest of IO code.

w1_search() is high-level protocol method, w1_io.c only contains
calls for low-level methods like bite/byte banging, reset, HW search and
so on.

> w1-master-drop-attrs.patch
> Get rid of unneeded master device attributes:
> - 'pointer' and 'attempts' are meaningless for userspace;
> - information provided by 'slaves' and 'slave_count' can be gathered
> from other sysfs bits;
> - w1_slave_found has to be rearranged now that slave_count field is gone.

attempts is usefull for broken lines.
pointer was definitely for debug, it can be removed now.

> w1-master-attr-cleanup.patch
> Clean-up master attribute implementation:
> - drop unnecessary "w1_master" prefix from attribute names;
> - do not acquire master->mutex when accessing attributes;
> - move attribute code "closer" to the rest of master code.

Ok, but slave count and slaves attributes itself requires that mutex.

> w1-master-scan-interval.patch
> More master attributes changes:
> - rename timeout parameter/attribute to scan_interval to better
> reflect its purpose;
> - make scan_timeout be a per-device attribute and allow changing
> it from userspace via sysfs;
> - allow changing max_slave_count it from userspace as well.

I like that change, but why do you ned to change the name?

> w1-master-add-ttl-attr.patch
> Add slave_ttl attribute to w1 masters.

Ok.

> w1-master-cleanup.patch
> Clean-up master device implementation:
> - get rid of separate refcount, rely on driver model to enforce
> lifetime rules;
> - use atomic to generate unique master IDs;
> - drop unused fields.

That patch is very broken.
I completely against it:
1. it breaks process logic - searching can be interrupted and stopped,
thread will exit on signals.
2. Your changes will break master/slave structure exporting.

> w1-slave-cleanup.patch
> Clean-up slave device implementation:
> - get rid of separate refcount, rely on driver model to enforce
> lifetime rules;
> - pin w1 module until slave device is registered with sysfs to make
> sure W1 core stays loaded.
> - drop 'name' attribute as we already have it in bus_id.

The same and even worse.

> w1-family-cleanup.patch
> Clean-up family implementation:
> - get rid of w1_family_ops and template attributes in w1_slave
> structure and have family drivers create necessary attributes
> themselves. There are too many different devices using 1-Wire
> interface and it is impossible to fit them all into single
> attribute model. If interface unification is needed it can be
> done by building cross-bus class hierarchy.
> - rename w1_smem to w1_sernum because devices are called Silicon
> serial numbers, they have address (ID) but don't have memory
> in regular sense.
> - rename w1_therm to w1_thermal.

smem == simple memory id, it is official name AFAIR.
Renames are superfluous, family_ops contains a "must have" operations,
driver writer can easily add it's own if it is needed.

> w1-family-is-driver.patch
> Convert family into proper device-model drivers:
> - embed driver structure into w1_family and register with the
> driver core;
> - do not try to manually bind slaves to familes, leave it to
> the driver core;
> - fold w1_family.c into w1.c

Why do you break it?
They were separated intentionally - it simplifies code review,
it is completely different logical models, family processing
is not hte same as slave.

> w1-device-id.patch
> Support for automatic family drivers loading via hotplug:
> - allow family drivers support list of families;
> - export supported families through MODULE_DEVICE_TABLE.
>
> w1-hotplug.patch
> Implement W1 bus hotplug handler. Slave devices will define
> FID=%02x (family ID) end SN=%024llX environment variables.

I'm against hotplug since it is too embedded world unfriendly :)
Actually it can be added, but as option, but not rely
the whole logic on it.

> w1-module-attrs.patch
> Allow changing w1 module parameters through sysfs, add parameter
> descriptions and document them in Documentation/kernel-parameters.txt
>
> Thanks!

Thank you very much for your changes and ideas,
but as you can see I'm against several of it.
The main reason is why dig into the driver model in a such way?
It will complicate strucutre exporting too much.
Existing locking/refcnt schema is very flexible and allows device
manipulation while it "holds" the reference counter,
and it will not be possible if one just blindly gets/puts module's
refcnt.
Object has reference counter which is incremented and decremented when
object is in use, not the whole module reference counter,
one may remove and add separate objects without knowledge of
what family or bus master driver handles that.
Your changes mix low-level driver logic with w1 core.
You have removed netlink notification and replace it with hotplug,
but it can not be used for systems without shell userspace support.

I will manually apply safe changes after Adrians changes
when Greg ACKs current pending patches.

--
Evgeniy Polyakov

Crash is better than data corruption -- Arthur Grabowski


Attachments:
signature.asc (189.00 B)
This is a digitally signed message part

2005-04-21 14:32:10

by Dmitry Torokhov

[permalink] [raw]
Subject: Re: [RFC/PATCH 0/22] W1: sysfs, lifetime and other fixes

Hi Evgeniy,

On 4/21/05, Evgeniy Polyakov <[email protected]> wrote:
> On Thu, 2005-04-21 at 02:07 -0500, Dmitry Torokhov wrote:
> > Hi,
>
> Hello, Dmitry.
>
> > I happened to take a look into drivers/w1 and found there bunch of thigs
> > that IMO should be changed:
> >
> > - custom-made refcounting is racy
>
> Why do you think so?
> Did you find exactly the place which races against something?
>
> > - lifetime rules need to be better enforced
>
> Hmm, I misunderstand you.
>

Consider thie following:

451 while (atomic_read(&sl->refcnt)) {
452 printk(KERN_INFO "Waiting for %s to become free:
refcnt=%d.\n",
453 sl->name, atomic_read(&sl->refcnt));
454
455 if (msleep_interruptible(1000))
456 flush_signals(current);
457 }
458
459 sysfs_remove_bin_file (&sl->dev.kobj, &sl->attr_bin);
460 device_remove_file(&sl->dev, &sl->attr_name);
461 device_remove_file(&sl->dev, &sl->attr_val);
462 device_unregister(&sl->dev);
463 w1_family_put(sl->family);
.. And caller does kfree(sl);

Now, if application opens slave's sysfs attribute while other thread
exited the loop and is about to remove attributes, then you will kfree
object that is in use and who knows what will happen. This is example
of both refcounting being racey and lifetime rules being violated.

> > - family framework is insufficient for many advanced w1 devices
>
> No, family framework is just indication which family is used.
> Feel free to implement additional methods for various devices
> and store them in driver's private areas like ipaq does.
>

OK, that is what I am aying. But why do you need that attribute with
variable name and a bin attribute that is not really bin but just a
dump for all kind of data (looks like debug one).

> > - custom-made hotplug notification over netlink should be removed in favor
> > of standard hotplug notification
>
> It is not hotplug, and your changes broke it completely.
> I'm waiting for connector to be included or discarded, so I can move
> w1 on top of it's interface or move connector's bits into the w1
> subsystem.
>

You will not be able to cram all 1-wire devices into unified
interface. You will need to build classes on top of it and you might
use connector (I am not sure) bit not on w1 bus level.
...
> > w1-slave-attr-group.patc
> > Add 2 default attributes "family" and "serial" to slave devices, every
> > 1-Wire slave has them. Use attribute_group to handle. The rest of slave
> > attributes are left as is - will be dealt with later.
>
> Serial number is already there in bus_id, family is there too.
> Why do you need separate files?

Yeah, could probably drop them.
...
> > w1-drop-owner.patch
> > Drop owner field from w1_master and w1_slave structures. Just having it
> > there does not magically fixes lifetime rules.
>
> They do not even pretend, I still do not understand what is "lifetime
> rules"?

So there is no point in having them, right?

>
> > w1-bus-ops.patch
> > Cleanup bus operations code:
> > - have bus operatiions accept w1_master instead of unsigned long and
> > drop data field from w1_bus_master so the structure can be statically
> > allocated by driver implementing it;
> > - rename w1_bus_master to w1_bus_ops to avoid confusion with w1_master;
> > - separate master registering and allocation so drivers can setup proper
> > link between private data and master and set useable master's name.
>
> I strongly object against such changes.
> 1. w1 was designed in the way that w1 bus master drivers do not
> know about other w1 world. It is very simple and very low-level
> abstraction,
> that only understands how to do low-level functions. It is not needed
> do know about w1_master structure and even about it's existence.

Well, it does need to know about w1_bus_master structure, which is
pretty much the same. And it allows having static bus_ops allocation
and removes need for casting from unsigned longs...

> 2. All renaming are superfluous, I'm not against it, but completely do
> not
> understand it's merits.

Because now it represents operations only, data field has been
dropped. I my head hurt when I see w1_master and w1_bus_muster
together as 2 separate objects both representing the same piece of
hardware.

> 3. You broke netlink allocation routing - it may fail and it is not
> fatal.

Because it is going away in later patcehs ;)

>
> > w1-fold-w1-int.patch
> > Fold w1_int.c into w1.c - there is no point in artificially separating
> > code for master devices between 2 files.
>
> w1_int.c was created to store external interface implementation,
> why do you want to move it into w1 core code?
> It will only soil the code...

Because I do not understand why code creating master devices is
separate from code creating master device's attributes.

>
> > w1-drop-netlink.patch
> > Drop custom-made hotplug over netlink notification from w1 core.
> > Standard hotplug mechanism should work just fine (patch will follow).
>
> netlink notification was not created for hotplug.
> Also I'm against w1 hotplug support, since hotplug is quite rarely used
> in embedded platforms where the majority of w1 devices live.

kobject_uevent does notification over netlink so I do not understand
why custom approach is better. You don't really need to use script.

> > w1-drop-control-thread.patch
> > Drop control thread from w1 core, whatever it does can also be done in
> > the context of w1_remove_master_device. Also, pin the module when
> > registering new master device to make sure that w1 core is not unloaded
> > until last device is gone. This simplifies logic a lot.
>
> Why do you think master can be removed in safe context only?

Can you show me example where you remove master from an interrupt
context or a tasklet? I doubt you will ever see one.

> I have feature requests for both adding/removing and exporting
> master devices and slaves to the external world.

External as in userspace? It (user thread) can wait just fine...

> Control thread is also the place in which we kick all devices
> when we need it, but not only when we need to remove w1 core module.

Define kicking for me please...

>
> > w1-move-search-to-io.patch
> > Move w1_search function to w1_io.c to be with the rest of IO code.
>
> w1_search() is high-level protocol method, w1_io.c only contains
> calls for low-level methods like bite/byte banging, reset, HW search and
> so on.

Well it does bit banging and completely foreign to the rest of w1
code. It may be high-level operation as fas as 1-wire on-wire protocol
goes, but it surely does not belong with kernel's W1 bus
implementattion code.

> > w1-master-attr-cleanup.patch
> > Clean-up master attribute implementation:
> > - drop unnecessary "w1_master" prefix from attribute names;
> > - do not acquire master->mutex when accessing attributes;
> > - move attribute code "closer" to the rest of master code.
>
> Ok, but slave count and slaves attributes itself requires that mutex.

They are gone. You can scan sysfs to get your slaves and count. Kernel
does not need to do that.

> > w1-master-scan-interval.patch
> > More master attributes changes:
> > - rename timeout parameter/attribute to scan_interval to better
> > reflect its purpose;
> > - make scan_timeout be a per-device attribute and allow changing
> > it from userspace via sysfs;
> > - allow changing max_slave_count it from userspace as well.
>
> I like that change, but why do you ned to change the name?

Because nothing times out (as in error). It defines interval between
scans -> scan_interval.

> > w1-master-cleanup.patch
> > Clean-up master device implementation:
> > - get rid of separate refcount, rely on driver model to enforce
> > lifetime rules;
> > - use atomic to generate unique master IDs;
> > - drop unused fields.
>
> That patch is very broken.
> I completely against it:
> 1. it breaks process logic - searching can be interrupted and stopped,
> thread will exit on signals.

Interrupted/stopped from userspace?

> 2. Your changes will break master/slave structure exporting.

-ENEEDMOREDATA.

>
> > w1-slave-cleanup.patch
> > Clean-up slave device implementation:
> > - get rid of separate refcount, rely on driver model to enforce
> > lifetime rules;
> > - pin w1 module until slave device is registered with sysfs to make
> > sure W1 core stays loaded.
> > - drop 'name' attribute as we already have it in bus_id.
>
> The same and even worse.

You need to fix lifetime rules.

> > w1-family-cleanup.patch
> > Clean-up family implementation:
> > - get rid of w1_family_ops and template attributes in w1_slave
> > structure and have family drivers create necessary attributes
> > themselves. There are too many different devices using 1-Wire
> > interface and it is impossible to fit them all into single
> > attribute model. If interface unification is needed it can be
> > done by building cross-bus class hierarchy.
> > - rename w1_smem to w1_sernum because devices are called Silicon
> > serial numbers, they have address (ID) but don't have memory
> > in regular sense.
> > - rename w1_therm to w1_thermal.
>
> smem == simple memory id, it is official name AFAIR.
> Renames are superfluous, family_ops contains a "must have" operations,
> driver writer can easily add it's own if it is needed.

What is so "must have" about 2 attributes? smem does not need anything
for exampe...

> > w1-family-is-driver.patch
> > Convert family into proper device-model drivers:
> > - embed driver structure into w1_family and register with the
> > driver core;
> > - do not try to manually bind slaves to familes, leave it to
> > the driver core;
> > - fold w1_family.c into w1.c
>
> Why do you break it?
> They were separated intentionally - it simplifies code review,
> it is completely different logical models, family processing
> is not hte same as slave.

Masters, slaves and families are all objects of W1 kernel bus. With
cutting a bunch of fat from family code it does not make sense to keep
them separate anymore.

>
> Thank you very much for your changes and ideas,
> but as you can see I'm against several of it.
> The main reason is why dig into the driver model in a such way?
> It will complicate strucutre exporting too much.

Because it is the standard for implementing devies and drivers in
linux kernel. You need to explain about exporting structure since the
rest of the system seem to be doing just fine.

> Existing locking/refcnt schema is very flexible and allows device
> manipulation while it "holds" the reference counter,

It is also racy and buggy.

> and it will not be possible if one just blindly gets/puts module's
> refcnt.

Only wire.ko is pinned. You are still free to remove family drivers or
master drivers (or killing their objects somehow). It is only core
that is pinned to make sure that release functions are available when
object finally goes away.

> Object has reference counter which is incremented and decremented when
> object is in use, not the whole module reference counter,
> one may remove and add separate objects without knowledge of
> what family or bus master driver handles that.

> Your changes mix low-level driver logic with w1 core.
> You have removed netlink notification and replace it with hotplug,
> but it can not be used for systems without shell userspace support.

kobject_uevent does not requere a sehll account.

Thank you for reviewing the patchset.

--
Dmitry

2005-04-21 16:09:39

by Dmitry Torokhov

[permalink] [raw]
Subject: Re: [RFC/PATCH 0/22] W1: sysfs, lifetime and other fixes

One more thing...

On 4/21/05, Evgeniy Polyakov <[email protected]> wrote:
> On Thu, 2005-04-21 at 02:07 -0500, Dmitry Torokhov wrote:
>
> > w1-master-drop-attrs.patch
> > Get rid of unneeded master device attributes:
> > - 'pointer' and 'attempts' are meaningless for userspace;
> > - information provided by 'slaves' and 'slave_count' can be gathered
> > from other sysfs bits;
> > - w1_slave_found has to be rearranged now that slave_count field is gone.
>
> attempts is usefull for broken lines.

It simply increments with every search i.e. every 10 secondsby default
and does not provide indication of the quality of the wire.

--
Dmitry

2005-04-25 09:10:49

by Evgeniy Polyakov

[permalink] [raw]
Subject: Re: [RFC/PATCH 0/22] W1: sysfs, lifetime and other fixes

On Thu, 2005-04-21 at 09:31 -0500, Dmitry Torokhov wrote:
> Hi Evgeniy,
>
> On 4/21/05, Evgeniy Polyakov <[email protected]> wrote:
> > On Thu, 2005-04-21 at 02:07 -0500, Dmitry Torokhov wrote:
> > > Hi,
> >
> > Hello, Dmitry.
> >
> > > I happened to take a look into drivers/w1 and found there bunch of thigs
> > > that IMO should be changed:
> > >
> > > - custom-made refcounting is racy
> >
> > Why do you think so?
> > Did you find exactly the place which races against something?
> >
> > > - lifetime rules need to be better enforced
> >
> > Hmm, I misunderstand you.
> >
>
> Consider thie following:
>
> 451 while (atomic_read(&sl->refcnt)) {
> 452 printk(KERN_INFO "Waiting for %s to become free:
> refcnt=%d.\n",
> 453 sl->name, atomic_read(&sl->refcnt));
> 454
> 455 if (msleep_interruptible(1000))
> 456 flush_signals(current);
> 457 }
> 458
> 459 sysfs_remove_bin_file (&sl->dev.kobj, &sl->attr_bin);
> 460 device_remove_file(&sl->dev, &sl->attr_name);
> 461 device_remove_file(&sl->dev, &sl->attr_val);
> 462 device_unregister(&sl->dev);
> 463 w1_family_put(sl->family);
> .. And caller does kfree(sl);
>
> Now, if application opens slave's sysfs attribute while other thread
> exited the loop and is about to remove attributes, then you will kfree
> object that is in use and who knows what will happen. This is example
> of both refcounting being racey and lifetime rules being violated.

Yes, I see now.
I will think of it some more...

> > > - family framework is insufficient for many advanced w1 devices
> >
> > No, family framework is just indication which family is used.
> > Feel free to implement additional methods for various devices
> > and store them in driver's private areas like ipaq does.
> >
>
> OK, that is what I am aying. But why do you need that attribute with
> variable name and a bin attribute that is not really bin but just a
> dump for all kind of data (looks like debug one).

bin attribute was created for lm_sensors scripts format - it only caches
read value.
I think there might be only 2 "must have" methods - read and write.
I plan to implement them using connector, so probably they will go away
completely.

> > > - custom-made hotplug notification over netlink should be removed in favor
> > > of standard hotplug notification
> >
> > It is not hotplug, and your changes broke it completely.
> > I'm waiting for connector to be included or discarded, so I can move
> > w1 on top of it's interface or move connector's bits into the w1
> > subsystem.
> >
>
> You will not be able to cram all 1-wire devices into unified
> interface. You will need to build classes on top of it and you might
> use connector (I am not sure) bit not on w1 bus level.
> ...

connector allows to have different objects inside one netlink group,
so it will use it in that way.
I think only two w1 methods must exist - read and write,
and they must follow protocol, defined in family driver.


> > > w1-drop-owner.patch
> > > Drop owner field from w1_master and w1_slave structures. Just having it
> > > there does not magically fixes lifetime rules.
> >
> > They do not even pretend, I still do not understand what is "lifetime
> > rules"?
>
> So there is no point in having them, right?

If I understand you correctly, "lifetime rules" are implemented in a
following way:
when object is created it has 0 refcnt, each access increments it and
must
decrements when access is finished.
According to mix of sysfs vs. current refcnt I see a possibility to
free object in ->relese()/remove() method and that is all, but I need to
investigate it more deeply.

> >
> > > w1-bus-ops.patch
> > > Cleanup bus operations code:
> > > - have bus operatiions accept w1_master instead of unsigned long and
> > > drop data field from w1_bus_master so the structure can be statically
> > > allocated by driver implementing it;
> > > - rename w1_bus_master to w1_bus_ops to avoid confusion with w1_master;
> > > - separate master registering and allocation so drivers can setup proper
> > > link between private data and master and set useable master's name.
> >
> > I strongly object against such changes.
> > 1. w1 was designed in the way that w1 bus master drivers do not
> > know about other w1 world. It is very simple and very low-level
> > abstraction,
> > that only understands how to do low-level functions. It is not needed
> > do know about w1_master structure and even about it's existence.
>
> Well, it does need to know about w1_bus_master structure, which is
> pretty much the same. And it allows having static bus_ops allocation
> and removes need for casting from unsigned longs...

w1_bus_master structure is low-level physical operations.
It _completely_ does not know abou logical links to other
w1 core objects, Why _bus_ driver should know about logical
objects on top of it? That is why they are separate.
Even if they are not too different (and actually they _are_ different)
from your point of view, they differ in abstration model.
Bus master driver - is like NIC driver, it does not know about the rest
of
the network stack, but you want it to have all info about neighbours,
routes
and so on...

> > 2. All renaming are superfluous, I'm not against it, but completely do
> > not
> > understand it's merits.
>
> Because now it represents operations only, data field has been
> dropped. I my head hurt when I see w1_master and w1_bus_muster
> together as 2 separate objects both representing the same piece of
> hardware.

No.

w1_bus_master is low-level driver for physical hardware operations.
w1_master is logical structure which is operated by w1 w1 core stack.
It has it's logical slaves, it has it's own attributes and features,
it _completely_ does not belong to low-level physical layer where you
want to place them both.

> > 3. You broke netlink allocation routing - it may fail and it is not
> > fatal.
>
> Because it is going away in later patcehs ;)

This is wrong - netlink notification is used and will be moved to
connector
interface later.

> >
> > > w1-fold-w1-int.patch
> > > Fold w1_int.c into w1.c - there is no point in artificially separating
> > > code for master devices between 2 files.
> >
> > w1_int.c was created to store external interface implementation,
> > why do you want to move it into w1 core code?
> > It will only soil the code...
>
> Because I do not understand why code creating master devices is
> separate from code creating master device's attributes.

It is better to move all attributes inside code creating master device
so place that attribute creating into w1_int.c

> >
> > > w1-drop-netlink.patch
> > > Drop custom-made hotplug over netlink notification from w1 core.
> > > Standard hotplug mechanism should work just fine (patch will follow).
> >
> > netlink notification was not created for hotplug.
> > Also I'm against w1 hotplug support, since hotplug is quite rarely used
> > in embedded platforms where the majority of w1 devices live.
>
> kobject_uevent does notification over netlink so I do not understand
> why custom approach is better. You don't really need to use script.

kobject is too big for that. It is used exactly for kobject changes.
Custom netlink notifications are created for w1 specific objects
and it's control. You can not control w1 slaves/masters using hotplug.

> > > w1-drop-control-thread.patch
> > > Drop control thread from w1 core, whatever it does can also be done in
> > > the context of w1_remove_master_device. Also, pin the module when
> > > registering new master device to make sure that w1 core is not unloaded
> > > until last device is gone. This simplifies logic a lot.
> >
> > Why do you think master can be removed in safe context only?
>
> Can you show me example where you remove master from an interrupt
> context or a tasklet? I doubt you will ever see one.

As I said I have feature requests for ability to export w1 devices
outside w1 core.
Probably it is due to it's private non-GPL usage, so it is not created,
but it is usefull feature actually and we can not know what will
happen in what context when we export master/slave devices.
w1 slaves can be found on the bus without search method reaction
implemented in it's asic, btw.
And it is _very_ usefull to add/remove slaves using external command but
not using
automatic detection in search methods.

> > I have feature requests for both adding/removing and exporting
> > master devices and slaves to the external world.
>
> External as in userspace? It (user thread) can wait just fine...

Exporting them into other kernel modules.
We do not know in what context that structures will be used there.

> > Control thread is also the place in which we kick all devices
> > when we need it, but not only when we need to remove w1 core module.
>
> Define kicking for me please...

Removing master device using netlink command for exaple.

> >
> > > w1-move-search-to-io.patch
> > > Move w1_search function to w1_io.c to be with the rest of IO code.
> >
> > w1_search() is high-level protocol method, w1_io.c only contains
> > calls for low-level methods like bite/byte banging, reset, HW search and
> > so on.
>
> Well it does bit banging and completely foreign to the rest of w1
> code. It may be high-level operation as fas as 1-wire on-wire protocol
> goes, but it surely does not belong with kernel's W1 bus
> implementattion code.

It does not only low-level operations,
but, well, probably it is better to place it there.

> > > w1-master-attr-cleanup.patch
> > > Clean-up master attribute implementation:
> > > - drop unnecessary "w1_master" prefix from attribute names;
> > > - do not acquire master->mutex when accessing attributes;
> > > - move attribute code "closer" to the rest of master code.
> >
> > Ok, but slave count and slaves attributes itself requires that mutex.
>
> They are gone. You can scan sysfs to get your slaves and count. Kernel
> does not need to do that.

I created that files exactly for reaason to not scan the tree, but only
read one [two] files :)

> > > w1-master-scan-interval.patch
> > > More master attributes changes:
> > > - rename timeout parameter/attribute to scan_interval to better
> > > reflect its purpose;
> > > - make scan_timeout be a per-device attribute and allow changing
> > > it from userspace via sysfs;
> > > - allow changing max_slave_count it from userspace as well.
> >
> > I like that change, but why do you ned to change the name?
>
> Because nothing times out (as in error). It defines interval between
> scans -> scan_interval.

Ok.

> > > w1-master-cleanup.patch
> > > Clean-up master device implementation:
> > > - get rid of separate refcount, rely on driver model to enforce
> > > lifetime rules;
> > > - use atomic to generate unique master IDs;
> > > - drop unused fields.
> >
> > That patch is very broken.
> > I completely against it:
> > 1. it breaks process logic - searching can be interrupted and stopped,
> > thread will exit on signals.
>
> Interrupted/stopped from userspace?

Your loop waits only until interrupt happens - it can be delivered from
anywhere.

> > 2. Your changes will break master/slave structure exporting.
>
> -ENEEDMOREDATA.

I think I described it in a master exporting paragraph, let's drop it
here.

> >
> > > w1-slave-cleanup.patch
> > > Clean-up slave device implementation:
> > > - get rid of separate refcount, rely on driver model to enforce
> > > lifetime rules;
> > > - pin w1 module until slave device is registered with sysfs to make
> > > sure W1 core stays loaded.
> > > - drop 'name' attribute as we already have it in bus_id.
> >
> > The same and even worse.
>
> You need to fix lifetime rules.

You moved all lto device model, while I want to have existing model
due to described actions.
So the right solution is to not break all existing locking, which
is mixed with device driver model, but create preper interoperability
model.
I will think of it some more, I will integrate your ad Adrian Bunk's
cleanups first when current pending patches are pushed.

> > > w1-family-cleanup.patch
> > > Clean-up family implementation:
> > > - get rid of w1_family_ops and template attributes in w1_slave
> > > structure and have family drivers create necessary attributes
> > > themselves. There are too many different devices using 1-Wire
> > > interface and it is impossible to fit them all into single
> > > attribute model. If interface unification is needed it can be
> > > done by building cross-bus class hierarchy.
> > > - rename w1_smem to w1_sernum because devices are called Silicon
> > > serial numbers, they have address (ID) but don't have memory
> > > in regular sense.
> > > - rename w1_therm to w1_thermal.
> >
> > smem == simple memory id, it is official name AFAIR.
> > Renames are superfluous, family_ops contains a "must have" operations,
> > driver writer can easily add it's own if it is needed.
>
> What is so "must have" about 2 attributes? smem does not need anything
> for exampe...

It is not read and read_bin, but read and write.
I have not implemented write methods monthes ago since I did not
have such a hardware, but now I see it was bad decision which
confused people.

> > > w1-family-is-driver.patch
> > > Convert family into proper device-model drivers:
> > > - embed driver structure into w1_family and register with the
> > > driver core;
> > > - do not try to manually bind slaves to familes, leave it to
> > > the driver core;
> > > - fold w1_family.c into w1.c
> >
> > Why do you break it?
> > They were separated intentionally - it simplifies code review,
> > it is completely different logical models, family processing
> > is not hte same as slave.
>
> Masters, slaves and families are all objects of W1 kernel bus. With
> cutting a bunch of fat from family code it does not make sense to keep
> them separate anymore.

What you do is exactly the same that already exist, but using other
model.
No need to dig into device model in a such way.

> > Thank you very much for your changes and ideas,
> > but as you can see I'm against several of it.
> > The main reason is why dig into the driver model in a such way?
> > It will complicate strucutre exporting too much.
>
> Because it is the standard for implementing devies and drivers in
> linux kernel. You need to explain about exporting structure since the
> rest of the system seem to be doing just fine.
>
> > Existing locking/refcnt schema is very flexible and allows device
> > manipulation while it "holds" the reference counter,
>
> It is also racy and buggy.

It is not.
You pointed an error, and it will be fixed after I think about it some
more,
the problem is that device model[which is not the main part of the w1
system]
is interfere to the existing locking schema [which is quite big and
allows very flexible object manipulation], and you suggest to almost
completely
replace one with another.
With such changes how to increment slave's usage counter? module_get
(w1_family)?

> > and it will not be possible if one just blindly gets/puts module's
> > refcnt.
>
> Only wire.ko is pinned. You are still free to remove family drivers or
> master drivers (or killing their objects somehow). It is only core
> that is pinned to make sure that release functions are available when
> object finally goes away.

If we remove slave deivice, we must be sure it's object is freed
when appripriate kobject is released.
The same is with family itself.

No, we need either replace all locking with device driver model,
or properly operate with existing one.
I will investigate it deeply, I'm sure will will find the best
solution.

> > Object has reference counter which is incremented and decremented when
> > object is in use, not the whole module reference counter,
> > one may remove and add separate objects without knowledge of
> > what family or bus master driver handles that.
>
> > Your changes mix low-level driver logic with w1 core.
> > You have removed netlink notification and replace it with hotplug,
> > but it can not be used for systems without shell userspace support.
>
> kobject_uevent does not requere a sehll account.

Exactly as existing netlink notifications, which allows
to bring not only simple predefined actions, but any information you
like.
As you said, we can not fit all existing w1 devices into very confined
limits, so hotplug events which are add/remove can not solve the
whole notification problem.
Simple notification mechanism that was created for w1 is only first
step,
of course it can be replaced with hotplug notification,
but only it, if we want, and I strongly believe we will want, to extend
it a bit we will fail with current hotplug approach.

--
Evgeniy Polyakov

Crash is better than data corruption -- Arthur Grabowski


Attachments:
signature.asc (189.00 B)
This is a digitally signed message part

2005-04-25 09:11:04

by Evgeniy Polyakov

[permalink] [raw]
Subject: Re: [RFC/PATCH 0/22] W1: sysfs, lifetime and other fixes

On Thu, 2005-04-21 at 11:09 -0500, Dmitry Torokhov wrote:
> One more thing...
>
> On 4/21/05, Evgeniy Polyakov <[email protected]> wrote:
> > On Thu, 2005-04-21 at 02:07 -0500, Dmitry Torokhov wrote:
> >
> > > w1-master-drop-attrs.patch
> > > Get rid of unneeded master device attributes:
> > > - 'pointer' and 'attempts' are meaningless for userspace;
> > > - information provided by 'slaves' and 'slave_count' can be gathered
> > > from other sysfs bits;
> > > - w1_slave_found has to be rearranged now that slave_count field is gone.
> >
> > attempts is usefull for broken lines.
>
> It simply increments with every search i.e. every 10 secondsby default
> and does not provide indication of the quality of the wire.

When slaves can not be found until several attempts, it means line
is broken, how many time existing slave appeared/dissapeared during
/sys/bus/w1/devices/w1_master1/attempts says about link quality.

--
Evgeniy Polyakov

Crash is better than data corruption -- Arthur Grabowski


Attachments:
signature.asc (189.00 B)
This is a digitally signed message part

2005-04-25 16:35:57

by Dmitry Torokhov

[permalink] [raw]
Subject: Re: [RFC/PATCH 0/22] W1: sysfs, lifetime and other fixes

On 4/25/05, Evgeniy Polyakov <[email protected]> wrote:
> On Thu, 2005-04-21 at 09:31 -0500, Dmitry Torokhov wrote:
> >
> > OK, that is what I am aying. But why do you need that attribute with
> > variable name and a bin attribute that is not really bin but just a
> > dump for all kind of data (looks like debug one).
>
> bin attribute was created for lm_sensors scripts format - it only caches
> read value.
> I think there might be only 2 "must have" methods - read and write.
> I plan to implement them using connector, so probably they will go away
> completely.
...
> > You will not be able to cram all 1-wire devices into unified
> > interface. You will need to build classes on top of it and you might
> > use connector (I am not sure) bit not on w1 bus level.
> > ...
>
> connector allows to have different objects inside one netlink group,
> so it will use it in that way.
> I think only two w1 methods must exist - read and write,
> and they must follow protocol, defined in family driver.

No, I think there should not be any "must have" methods on w1_bus
level. What you really need (and this needs to be coordinated with
other sensors people) is a "sensors" class hierarchy that will define
classes like "temperature sensor", "fan", "vid", etc. Then your w1
family drivers, when bound to a slave, will create needed class
devices. i2c drivers will do the same, and your superio, and I'll be
able to change i8k driver just for kicks. Then your usespace would not
care what _bus_ a particular sensor is sittign on and will be
presented with a unified interface. Look at your NIC example -
userspace does not care if NIC is sitting on a PCI, ISA, PCMCIA or USB
bus - it's all the same. And your classes can use netlink as a
transport mechanism - fine, why shouldn't they... But it will be
available for entire kernel, not only w1 bus..

Once again, bus code is not the right level to define interface with
userspace. There just way too many different devices acn be connected
to the same bus. You need to separate them into classes andd efine
interface tfor a class. And class does not have to be confined to a
signe bus, it can span across several buses, providing unified
interface to a group of similar objects.

...
> If I understand you correctly, "lifetime rules" are implemented in a
> following way:
> when object is created it has 0 refcnt, each access increments it and
> must
> decrements when access is finished.

No, not each access (well, depending on what you mean by access).
Normally, when you create an object you set it's refcount to 1 (becase
there is 1 owner - you). Evry time you pass that object to another
thread of execution (process) you need to increment reference count
and every time you donr with using object you decrement reference
count. Last user needs to destroy the object. See
Documentation/kref.txt

> > >
> > > > w1-bus-ops.patch
> > > > Cleanup bus operations code:
> > > > - have bus operatiions accept w1_master instead of unsigned long and
> > > > drop data field from w1_bus_master so the structure can be statically
> > > > allocated by driver implementing it;
> > > > - rename w1_bus_master to w1_bus_ops to avoid confusion with w1_master;
> > > > - separate master registering and allocation so drivers can setup proper
> > > > link between private data and master and set useable master's name.
> > >
> > > I strongly object against such changes.
> > > 1. w1 was designed in the way that w1 bus master drivers do not
> > > know about other w1 world. It is very simple and very low-level
> > > abstraction,
> > > that only understands how to do low-level functions. It is not needed
> > > do know about w1_master structure and even about it's existence.
> >
> > Well, it does need to know about w1_bus_master structure, which is
> > pretty much the same. And it allows having static bus_ops allocation
> > and removes need for casting from unsigned longs...
>
> w1_bus_master structure is low-level physical operations.
> It _completely_ does not know abou logical links to other
> w1 core objects, Why _bus_ driver should know about logical
> objects on top of it? That is why they are separate.
> Even if they are not too different (and actually they _are_ different)
> from your point of view, they differ in abstration model.
> Bus master driver - is like NIC driver, it does not know about the rest
> of
> the network stack, but you want it to have all info about neighbours,
> routes
> and so on...
>

Ok, look at the drivers implementiog NICs - struct netdevice. The
define open() and close() methods, but they also know a little bit
about netdevice, like how to get rivate data (netdev_priv) and some
other stuff. That is exactly what I have done WRT w1_master and
w1_bus_master. Again, this allows to have w1_bus_master (w1_bus_ops)
statically allocated and not piggy-back it to w1_master memory
allocation. And we not have better type-safety because we don't pass
unsigned longs and up/down cast them everywhere. And you don't need to
"search" for a master device using "data" as a cookie. If you want we
can have w1_master_priv to access w1_master->priv instead of
referencing it directly.

> > > 3. You broke netlink allocation routing - it may fail and it is not
> > > fatal.
> >
> > Because it is going away in later patcehs ;)
>
> This is wrong - netlink notification is used and will be moved to
> connector
> interface later.

But not at the w1_bus level, please.

> > >
> > > > w1-drop-netlink.patch
> > > > Drop custom-made hotplug over netlink notification from w1 core.
> > > > Standard hotplug mechanism should work just fine (patch will follow).
> > >
> > > netlink notification was not created for hotplug.
> > > Also I'm against w1 hotplug support, since hotplug is quite rarely used
> > > in embedded platforms where the majority of w1 devices live.
> >
> > kobject_uevent does notification over netlink so I do not understand
> > why custom approach is better. You don't really need to use script.
>
> kobject is too big for that. It is used exactly for kobject changes.
> Custom netlink notifications are created for w1 specific objects
> and it's control. You can not control w1 slaves/masters using hotplug.

Hotplug is a unified mechanism for notifying userspace of new devices.
Not only on w1 bus but everywhere. Stop inventing solutions useable
for w1 bus only. And if I for some reason don't want to use netlink -
well I can with gebneric hotplug solution but not with your.

> > > > w1-drop-control-thread.patch
> > > > Drop control thread from w1 core, whatever it does can also be done in
> > > > the context of w1_remove_master_device. Also, pin the module when
> > > > registering new master device to make sure that w1 core is not unloaded
> > > > until last device is gone. This simplifies logic a lot.
> > >
> > > Why do you think master can be removed in safe context only?
> >
> > Can you show me example where you remove master from an interrupt
> > context or a tasklet? I doubt you will ever see one.
>
> As I said I have feature requests for ability to export w1 devices
> outside w1 core.
> Probably it is due to it's private non-GPL usage, so it is not created,
> but it is usefull feature actually and we can not know what will
> happen in what context when we export master/slave devices.

Look at your present w1_remove_master_device. It sleeps. Sop there is
no need for a separate thread, callers must be able to sleep anyway.

> w1 slaves can be found on the bus without search method reaction
> implemented in it's asic, btw.
> And it is _very_ usefull to add/remove slaves using external command but
> not using
> automatic detection in search methods.

But the request for that will come from userspace with is perfectly
able to sleep. You are over-engineering and making kernel code
unnecessarily complex without thinking it through.

> > > I have feature requests for both adding/removing and exporting
> > > master devices and slaves to the external world.
> >
> > External as in userspace? It (user thread) can wait just fine...
>
> Exporting them into other kernel modules.
> We do not know in what context that structures will be used there.

Why other kernel modules would be interested in raw access w1_slaves?
C are to give an example?

> > > Control thread is also the place in which we kick all devices
> > > when we need it, but not only when we need to remove w1 core module.
> >
> > Define kicking for me please...
>
> Removing master device using netlink command for exaple.

Wrong level. You need to start with device implementing w1_bus_master
(w1_bus_ops) to remova dangling data structures). Easiest way I think
it have the driver compiled as a module and remove it altogether - why
keep it if you don't need master?

> > > > w1-master-attr-cleanup.patch
> > > > Clean-up master attribute implementation:
> > > > - drop unnecessary "w1_master" prefix from attribute names;
> > > > - do not acquire master->mutex when accessing attributes;
> > > > - move attribute code "closer" to the rest of master code.
> > >
> > > Ok, but slave count and slaves attributes itself requires that mutex.
> >
> > They are gone. You can scan sysfs to get your slaves and count. Kernel
> > does not need to do that.
>
> I created that files exactly for reaason to not scan the tree, but only
> read one [two] files :)

The less code in kernel that produces data availavle elsewhere the better :)

> > > > w1-master-cleanup.patch
> > > > Clean-up master device implementation:
> > > > - get rid of separate refcount, rely on driver model to enforce
> > > > lifetime rules;
> > > > - use atomic to generate unique master IDs;
> > > > - drop unused fields.
> > >
> > > That patch is very broken.
> > > I completely against it:
> > > 1. it breaks process logic - searching can be interrupted and stopped,
> > > thread will exit on signals.
> >
> > Interrupted/stopped from userspace?
>
> Your loop waits only until interrupt happens - it can be delivered from
> anywhere.

No, only root can kill kernel therad so it is pretty safe. And hey, if
a thread goes mad maybe it's a good thing that it can be killed.

> > > > w1-family-is-driver.patch
> > > > Convert family into proper device-model drivers:
> > > > - embed driver structure into w1_family and register with the
> > > > driver core;
> > > > - do not try to manually bind slaves to familes, leave it to
> > > > the driver core;
> > > > - fold w1_family.c into w1.c
> > >
> > > Why do you break it?
> > > They were separated intentionally - it simplifies code review,
> > > it is completely different logical models, family processing
> > > is not hte same as slave.
> >
> > Masters, slaves and families are all objects of W1 kernel bus. With
> > cutting a bunch of fat from family code it does not make sense to keep
> > them separate anymore.
>
> What you do is exactly the same that already exist, but using other
> model.
> No need to dig into device model in a such way.
...
> the problem is that device model[which is not the main part of the w1
> system]
> is interfere to the existing locking schema [which is quite big and
> allows very flexible object manipulation], and you suggest to almost
> completely
> replace one with another.

device model is here to _use_ it. It already implements bunch of stuff
you have to re-implement if you do it "your own way" and it is already
debugged much better than your solution. And if there is a problem
with driver core implementation - well, more people are looking at it
and are more likely to discover a problem and offer a solution.

I do not understand why you are against full integration with device
model - it does simplifies and unifies the code.

> With such changes how to increment slave's usage counter? module_get
> (w1_family)?

Actually if you need it it would be get_device(&w1_slave->dev). And if
you need pin family object you would get
get_driver(&w1_family->driver). But I don't think you will needed it.
Actually, at some point I had w1_family_get() implemented as a wrapper
to get_driver() but since it does not seem to be needed I dropped it.

> > > and it will not be possible if one just blindly gets/puts module's
> > > refcnt.
> >
> > Only wire.ko is pinned. You are still free to remove family drivers or
> > master drivers (or killing their objects somehow). It is only core
> > that is pinned to make sure that release functions are available when
> > object finally goes away.
>
> If we remove slave deivice, we must be sure it's object is freed
> when appripriate kobject is released.
> The same is with family itself.

Right.

> No, we need either replace all locking with device driver model,
> or properly operate with existing one.

And it was done. Well, not locking, but pinning of the objects. It was
all moved to device model. It may not be visible ;) but it is there.
Locking is still there as well.

--
Dmitry

2005-04-25 16:40:17

by Dmitry Torokhov

[permalink] [raw]
Subject: Re: [RFC/PATCH 0/22] W1: sysfs, lifetime and other fixes

On 4/25/05, Evgeniy Polyakov <[email protected]> wrote:
> On Thu, 2005-04-21 at 11:09 -0500, Dmitry Torokhov wrote:
> > One more thing...
> >
> > On 4/21/05, Evgeniy Polyakov <[email protected]> wrote:
> > > On Thu, 2005-04-21 at 02:07 -0500, Dmitry Torokhov wrote:
> > >
> > > > w1-master-drop-attrs.patch
> > > > Get rid of unneeded master device attributes:
> > > > - 'pointer' and 'attempts' are meaningless for userspace;
> > > > - information provided by 'slaves' and 'slave_count' can be gathered
> > > > from other sysfs bits;
> > > > - w1_slave_found has to be rearranged now that slave_count field is gone.
> > >
> > > attempts is usefull for broken lines.
> >
> > It simply increments with every search i.e. every 10 secondsby default
> > and does not provide indication of the quality of the wire.
>
> When slaves can not be found until several attempts, it means line
> is broken, how many time existing slave appeared/dissapeared during
> /sys/bus/w1/devices/w1_master1/attempts says about link quality.

Heh, if you are debugging all you need is "date" command to see how
quickly slave appears. If you want to keep statistics your program
need to listen to hotpug events for master and slaves and count these.
I do not see a reason for a counter that simply increments every 10
seconds.

--
Dmitry

2005-04-25 19:30:32

by Evgeniy Polyakov

[permalink] [raw]
Subject: Re: [RFC/PATCH 0/22] W1: sysfs, lifetime and other fixes

On Mon, 25 Apr 2005 11:32:14 -0500
Dmitry Torokhov <[email protected]> wrote:

> On 4/25/05, Evgeniy Polyakov <[email protected]> wrote:
> > On Thu, 2005-04-21 at 09:31 -0500, Dmitry Torokhov wrote:
> > >
> > > OK, that is what I am aying. But why do you need that attribute with
> > > variable name and a bin attribute that is not really bin but just a
> > > dump for all kind of data (looks like debug one).
> >
> > bin attribute was created for lm_sensors scripts format - it only caches
> > read value.
> > I think there might be only 2 "must have" methods - read and write.
> > I plan to implement them using connector, so probably they will go away
> > completely.
> ...
> > > You will not be able to cram all 1-wire devices into unified
> > > interface. You will need to build classes on top of it and you might
> > > use connector (I am not sure) bit not on w1 bus level.
> > > ...
> >
> > connector allows to have different objects inside one netlink group,
> > so it will use it in that way.
> > I think only two w1 methods must exist - read and write,
> > and they must follow protocol, defined in family driver.
>
> No, I think there should not be any "must have" methods on w1_bus
> level. What you really need (and this needs to be coordinated with
> other sensors people) is a "sensors" class hierarchy that will define
> classes like "temperature sensor", "fan", "vid", etc. Then your w1
> family drivers, when bound to a slave, will create needed class
> devices. i2c drivers will do the same, and your superio, and I'll be
> able to change i8k driver just for kicks. Then your usespace would not
> care what _bus_ a particular sensor is sittign on and will be
> presented with a unified interface. Look at your NIC example -
> userspace does not care if NIC is sitting on a PCI, ISA, PCMCIA or USB
> bus - it's all the same. And your classes can use netlink as a
> transport mechanism - fine, why shouldn't they... But it will be
> available for entire kernel, not only w1 bus..
>
> Once again, bus code is not the right level to define interface with
> userspace. There just way too many different devices acn be connected
> to the same bus. You need to separate them into classes andd efine
> interface tfor a class. And class does not have to be confined to a
> signe bus, it can span across several buses, providing unified
> interface to a group of similar objects.

Heh, that would be nice, but that requires a _lot_ of changes,
so it is only theory, at least for now.

Reality is that w1 devices must be managed from userspace,
it can be implemented using 2 system calls - read and write,
while they are implemented using sysfs and thus device/driver model,
it requires different locking, which may race - and I will fix it.
Other implementation could be connector's calls - they
can be used in i2c core and _are_ used in superio core,
it will put it into w1 if it will be commited in.
Probably implementation will be similar to superio one...

> ...
> > If I understand you correctly, "lifetime rules" are implemented in a
> > following way:
> > when object is created it has 0 refcnt, each access increments it and
> > must
> > decrements when access is finished.
>
> No, not each access (well, depending on what you mean by access).
> Normally, when you create an object you set it's refcount to 1 (becase
> there is 1 owner - you). Evry time you pass that object to another
> thread of execution (process) you need to increment reference count
> and every time you donr with using object you decrement reference
> count. Last user needs to destroy the object. See
> Documentation/kref.txt

The behaviour exactly the same, but implementation always
waits on remove when others finish. No problem here.

> > > >
> > > > > w1-bus-ops.patch
> > > > > Cleanup bus operations code:
> > > > > - have bus operatiions accept w1_master instead of unsigned long and
> > > > > drop data field from w1_bus_master so the structure can be statically
> > > > > allocated by driver implementing it;
> > > > > - rename w1_bus_master to w1_bus_ops to avoid confusion with w1_master;
> > > > > - separate master registering and allocation so drivers can setup proper
> > > > > link between private data and master and set useable master's name.
> > > >
> > > > I strongly object against such changes.
> > > > 1. w1 was designed in the way that w1 bus master drivers do not
> > > > know about other w1 world. It is very simple and very low-level
> > > > abstraction,
> > > > that only understands how to do low-level functions. It is not needed
> > > > do know about w1_master structure and even about it's existence.
> > >
> > > Well, it does need to know about w1_bus_master structure, which is
> > > pretty much the same. And it allows having static bus_ops allocation
> > > and removes need for casting from unsigned longs...
> >
> > w1_bus_master structure is low-level physical operations.
> > It _completely_ does not know abou logical links to other
> > w1 core objects, Why _bus_ driver should know about logical
> > objects on top of it? That is why they are separate.
> > Even if they are not too different (and actually they _are_ different)
> > from your point of view, they differ in abstration model.
> > Bus master driver - is like NIC driver, it does not know about the rest
> > of
> > the network stack, but you want it to have all info about neighbours,
> > routes
> > and so on...
> >
>
> Ok, look at the drivers implementiog NICs - struct netdevice. The
> define open() and close() methods, but they also know a little bit
> about netdevice, like how to get rivate data (netdev_priv) and some
> other stuff. That is exactly what I have done WRT w1_master and
> w1_bus_master. Again, this allows to have w1_bus_master (w1_bus_ops)
> statically allocated and not piggy-back it to w1_master memory
> allocation. And we not have better type-safety because we don't pass
> unsigned longs and up/down cast them everywhere. And you don't need to
> "search" for a master device using "data" as a cookie. If you want we
> can have w1_master_priv to access w1_master->priv instead of
> referencing it directly.

Neither network driver knows about how skb are used.
NIC's device driver does not know about neighbours, routes, filters and so on.
It only moves data to the physical layer, how data is managed over it
is not in driver's competence.
w1 bus master driver only knows how to move data to the wire,
it does not know about how that data was moved there, from/to which
slave it is originated and so on.

Bus master driver is low-level part that lives in it's own driver,
while w1 core only knows about higher-layer w1_master objects.
Like network stack operates on device driver (in our case it is
w1 bus master driver) through dev->something(), and we have
here dev->bus_master->something(), network core operates
over routes using dst/rt - w1 has dev->slist and so on.
You may say that why call through dev->bus_master->something()
when we may call dev->something(), I can say that
w1_master itself is like a stack in network -
it knows about it's routes (slave devices),
it knows about it's low-level driver (bus master),
it has proper locking (xmit lock in network).

Bus master driver is absolutely separate object
from w1_master structure and logical object itself.

> > > > 3. You broke netlink allocation routing - it may fail and it is not
> > > > fatal.
> > >
> > > Because it is going away in later patcehs ;)
> >
> > This is wrong - netlink notification is used and will be moved to
> > connector
> > interface later.
>
> But not at the w1_bus level, please.

How do you suppose to notify about alarm condition?
Not from bus layer?
Who does send "link is down" messages? It is not the same
as device is present and found, it like "w1 device has something to read".
For example w1 ds18s20 thermal sensor may send information
about "85 degree problem" - it is read when sensor did not
finished temerature transformation yet, how non-bus layer may know about it?

Your idea about classes over the various buses is good,
but unfortunately it is utopia, al least for now,
so let's create w1 core layer (which, btw, is not only bus,
which is managed by bus master dirver, but also some logic over it,
one may call it w1 stack, stack can send such a messages, doesn't it)?

> > > >
> > > > > w1-drop-netlink.patch
> > > > > Drop custom-made hotplug over netlink notification from w1 core.
> > > > > Standard hotplug mechanism should work just fine (patch will follow).
> > > >
> > > > netlink notification was not created for hotplug.
> > > > Also I'm against w1 hotplug support, since hotplug is quite rarely used
> > > > in embedded platforms where the majority of w1 devices live.
> > >
> > > kobject_uevent does notification over netlink so I do not understand
> > > why custom approach is better. You don't really need to use script.
> >
> > kobject is too big for that. It is used exactly for kobject changes.
> > Custom netlink notifications are created for w1 specific objects
> > and it's control. You can not control w1 slaves/masters using hotplug.
>
> Hotplug is a unified mechanism for notifying userspace of new devices.
> Not only on w1 bus but everywhere. Stop inventing solutions useable
> for w1 bus only. And if I for some reason don't want to use netlink -
> well I can with gebneric hotplug solution but not with your.

The problem is that there is not only exist/not events, that may be sent,
as I said in previous mail.
You suggest to limit it in that way - this is wrong.
Feel free to _add_ hotplug support, but not replace notification with it.

> > > > > w1-drop-control-thread.patch
> > > > > Drop control thread from w1 core, whatever it does can also be done in
> > > > > the context of w1_remove_master_device. Also, pin the module when
> > > > > registering new master device to make sure that w1 core is not unloaded
> > > > > until last device is gone. This simplifies logic a lot.
> > > >
> > > > Why do you think master can be removed in safe context only?
> > >
> > > Can you show me example where you remove master from an interrupt
> > > context or a tasklet? I doubt you will ever see one.
> >
> > As I said I have feature requests for ability to export w1 devices
> > outside w1 core.
> > Probably it is due to it's private non-GPL usage, so it is not created,
> > but it is usefull feature actually and we can not know what will
> > happen in what context when we export master/slave devices.
>
> Look at your present w1_remove_master_device. It sleeps. Sop there is
> no need for a separate thread, callers must be able to sleep anyway.


That is exactly why control thread exists - to manage sleepable operations!


> > w1 slaves can be found on the bus without search method reaction
> > implemented in it's asic, btw.
> > And it is _very_ usefull to add/remove slaves using external command but
> > not using
> > automatic detection in search methods.
>
> But the request for that will come from userspace with is perfectly
> able to sleep. You are over-engineering and making kernel code
> unnecessarily complex without thinking it through.

Connector's requests come from BH context.
Only module unloading comes with good context (in our case we do not
get read/write operations),
but I do not want to limit the system only for that kinds of events.

> > > > I have feature requests for both adding/removing and exporting
> > > > master devices and slaves to the external world.
> > >
> > > External as in userspace? It (user thread) can wait just fine...
> >
> > Exporting them into other kernel modules.
> > We do not know in what context that structures will be used there.
>
> Why other kernel modules would be interested in raw access w1_slaves?
> C are to give an example?

Concider w1 battery slave device, which exports unified interface to
the userspace.
It requires access that can be obtained from different generic module
[like existing kernelspace/userspace protocol,
proper device files and so on],
which will implement only read/write interface.
It's read method will get_slave_by_something() and read it's data
or do something else, then generic module will use that data.

Generic buttery monitor will not scan w1 bus for it's devices,
since it even does not know about w1, it only understands reading/writing
operations.

Placing operations needed for that module into w1_bat.c and hope
that noone will implement new battery monitor subsystem
or will adopt all battery users to use only that nterface is naive.

There is at least _possibility_ to create such a model
with existing design [and it is _very_ easy],
but your changes broke it, although it could be changed...

> > > > Control thread is also the place in which we kick all devices
> > > > when we need it, but not only when we need to remove w1 core module.
> > >
> > > Define kicking for me please...
> >
> > Removing master device using netlink command for exaple.
>
> Wrong level. You need to start with device implementing w1_bus_master
> (w1_bus_ops) to remova dangling data structures). Easiest way I think
> it have the driver compiled as a module and remove it altogether - why
> keep it if you don't need master?

1. master can be removed by command. It is not in process' context.
Current thread can remove only all object at once, but nevertheless
I do not want to limit it.
2. control thread can add/remove new slaves by request.
Usefullness of that ability was pointed in my previous e-mail,
but you skipped that part.

> > > > > w1-master-attr-cleanup.patch
> > > > > Clean-up master attribute implementation:
> > > > > - drop unnecessary "w1_master" prefix from attribute names;
> > > > > - do not acquire master->mutex when accessing attributes;
> > > > > - move attribute code "closer" to the rest of master code.
> > > >
> > > > Ok, but slave count and slaves attributes itself requires that mutex.
> > >
> > > They are gone. You can scan sysfs to get your slaves and count. Kernel
> > > does not need to do that.
> >
> > I created that files exactly for reaason to not scan the tree, but only
> > read one [two] files :)
>
> The less code in kernel that produces data availavle elsewhere the better :)

Does 3 lines of code for reading slave's names is too big
price for not scanning the whole /sys/bus/w1/w1_master1/ directory?


> > > > > w1-master-cleanup.patch
> > > > > Clean-up master device implementation:
> > > > > - get rid of separate refcount, rely on driver model to enforce
> > > > > lifetime rules;
> > > > > - use atomic to generate unique master IDs;
> > > > > - drop unused fields.
> > > >
> > > > That patch is very broken.
> > > > I completely against it:
> > > > 1. it breaks process logic - searching can be interrupted and stopped,
> > > > thread will exit on signals.
> > >
> > > Interrupted/stopped from userspace?
> >
> > Your loop waits only until interrupt happens - it can be delivered from
> > anywhere.
>
> No, only root can kill kernel therad so it is pretty safe. And hey, if
> a thread goes mad maybe it's a good thing that it can be killed.

And if it exits - it breaks the logic - user can not know the state
of the master device when thread is exited, but module was not removed
by request.

> > > > > w1-family-is-driver.patch
> > > > > Convert family into proper device-model drivers:
> > > > > - embed driver structure into w1_family and register with the
> > > > > driver core;
> > > > > - do not try to manually bind slaves to familes, leave it to
> > > > > the driver core;
> > > > > - fold w1_family.c into w1.c
> > > >
> > > > Why do you break it?
> > > > They were separated intentionally - it simplifies code review,
> > > > it is completely different logical models, family processing
> > > > is not hte same as slave.
> > >
> > > Masters, slaves and families are all objects of W1 kernel bus. With
> > > cutting a bunch of fat from family code it does not make sense to keep
> > > them separate anymore.
> >
> > What you do is exactly the same that already exist, but using other
> > model.
> > No need to dig into device model in a such way.
> ...
> > the problem is that device model[which is not the main part of the w1
> > system]
> > is interfere to the existing locking schema [which is quite big and
> > allows very flexible object manipulation], and you suggest to almost
> > completely
> > replace one with another.
>
> device model is here to _use_ it. It already implements bunch of stuff
> you have to re-implement if you do it "your own way" and it is already
> debugged much better than your solution. And if there is a problem
> with driver core implementation - well, more people are looking at it
> and are more likely to discover a problem and offer a solution.
>
> I do not understand why you are against full integration with device
> model - it does simplifies and unifies the code.

Because it is not needed here - and even if it could be integrated
more closer - your changes broke too many special design cases,
which are not acceptible.

> > With such changes how to increment slave's usage counter? module_get
> > (w1_family)?
>
> Actually if you need it it would be get_device(&w1_slave->dev). And if
> you need pin family object you would get
> get_driver(&w1_family->driver). But I don't think you will needed it.
> Actually, at some point I had w1_family_get() implemented as a wrapper
> to get_driver() but since it does not seem to be needed I dropped it.

We can not do it in that way.
1. low-level bus master code differs from what w1_master is.
2. family itself is different from slave object.

Having that we need to create w1_master/w1_family device/driver model
locking + w1_bus_master/w1_slave locking or move them to device/driver
model too. Why it is needed I still do not see, there is
proper locking schema, which is broken in the places where
existing model touches device/driver one, and it will be fixed.

> > > > and it will not be possible if one just blindly gets/puts module's
> > > > refcnt.
> > >
> > > Only wire.ko is pinned. You are still free to remove family drivers or
> > > master drivers (or killing their objects somehow). It is only core
> > > that is pinned to make sure that release functions are available when
> > > object finally goes away.
> >
> > If we remove slave deivice, we must be sure it's object is freed
> > when appripriate kobject is released.
> > The same is with family itself.
>
> Right.
>
> > No, we need either replace all locking with device driver model,
> > or properly operate with existing one.
>
> And it was done. Well, not locking, but pinning of the objects. It was
> all moved to device model. It may not be visible ;) but it is there.
> Locking is still there as well.

We need here either _only_ device/driver locking (locking here and above
is not only locking itself, but usage counters and all corresponding events
too), or mix of the existing schema and device/driver model.
The first approach already has too many issues, which
probably can be resolved, but probably dont, existing mixing
model works except one case, which I will fix.
It will use device/driver model and it's remove callback
to free resources.


Now I have folowing agenda for w1:
1. wait until existing changes are commited
2. put your's and Adrian's cleanups
3. fix w1 sysfs usage
4. commit 2 and 3
5. implement hotplug using your patch, but not instead of existing notification.
6. commit hotplug changes

I strongly believe that after [3] there will be no moot points.


Thank you.

> --
> Dmitry


Evgeniy Polyakov

Only failure makes us experts. -- Theo de Raadt

2005-04-25 19:35:27

by Evgeniy Polyakov

[permalink] [raw]
Subject: Re: [RFC/PATCH 0/22] W1: sysfs, lifetime and other fixes

On Mon, 25 Apr 2005 11:36:05 -0500
Dmitry Torokhov <[email protected]> wrote:

> On 4/25/05, Evgeniy Polyakov <[email protected]> wrote:
> > On Thu, 2005-04-21 at 11:09 -0500, Dmitry Torokhov wrote:
> > > One more thing...
> > >
> > > On 4/21/05, Evgeniy Polyakov <[email protected]> wrote:
> > > > On Thu, 2005-04-21 at 02:07 -0500, Dmitry Torokhov wrote:
> > > >
> > > > > w1-master-drop-attrs.patch
> > > > > Get rid of unneeded master device attributes:
> > > > > - 'pointer' and 'attempts' are meaningless for userspace;
> > > > > - information provided by 'slaves' and 'slave_count' can be gathered
> > > > > from other sysfs bits;
> > > > > - w1_slave_found has to be rearranged now that slave_count field is gone.
> > > >
> > > > attempts is usefull for broken lines.
> > >
> > > It simply increments with every search i.e. every 10 secondsby default
> > > and does not provide indication of the quality of the wire.
> >
> > When slaves can not be found until several attempts, it means line
> > is broken, how many time existing slave appeared/dissapeared during
> > /sys/bus/w1/devices/w1_master1/attempts says about link quality.
>
> Heh, if you are debugging all you need is "date" command to see how
> quickly slave appears. If you want to keep statistics your program
> need to listen to hotpug events for master and slaves and count these.
> I do not see a reason for a counter that simply increments every 10
> seconds.

It is not counter but attempt does matter, one of course can simply
calculate attempt number using timeout value, but that requires
timeout knowledge, which is not accessible after driver is loaded.

> --
> Dmitry


Evgeniy Polyakov

Only failure makes us experts. -- Theo de Raadt

2005-04-25 20:19:16

by Evgeniy Polyakov

[permalink] [raw]
Subject: Re: [RFC/PATCH 0/22] W1: sysfs, lifetime and other fixes

While thinking about locking schema
with respect to sysfs files I recalled,
why I implemented such a logic -
now one can _always_ remove _any_ module
[corresponding object is removed from accessible
pathes and waits untill all exsting users are gone],
which is very good - I really like it in networking model,
while with whole device driver model
if we will read device's file very quickly
in several threads we may end up not unloading it at all.

So decision is simple from the first point of view -
just remove appropriate objects from accessible pathes
and free them from finall callbacks [device's remove method].

Evgeniy Polyakov

Only failure makes us experts. -- Theo de Raadt

2005-04-25 20:24:44

by Dmitry Torokhov

[permalink] [raw]
Subject: Re: [RFC/PATCH 0/22] W1: sysfs, lifetime and other fixes

On 4/25/05, Evgeniy Polyakov <[email protected]> wrote:
> While thinking about locking schema
> with respect to sysfs files I recalled,
> why I implemented such a logic -
> now one can _always_ remove _any_ module
> [corresponding object is removed from accessible
> pathes and waits untill all exsting users are gone],
> which is very good - I really like it in networking model,
> while with whole device driver model
> if we will read device's file very quickly
> in several threads we may end up not unloading it at all.

I am sorrry, that is complete bull*. sysfs also allows removing
modules at an arbitrary time (and usually without annoying "waiting
for refcount" at that)... You just seem to not understand how driver
code works, thus the need of inventing your own schema.

BTW, I am looking at the connector code ATM and I am just amazed at
all wied refounting stuff that is going on there. what a single
actomic_dec_and_test() call without checkng reurn vaue is supposed to
do again?

--
Dmitry

2005-04-25 21:36:50

by Dmitry Torokhov

[permalink] [raw]
Subject: Re: [RFC/PATCH 0/22] W1: sysfs, lifetime and other fixes

On 4/25/05, Evgeniy Polyakov <[email protected]> wrote:
>
> How do you suppose to notify about alarm condition?
> Not from bus layer?
> Who does send "link is down" messages? It is not the same
> as device is present and found, it like "w1 device has something to read".
> For example w1 ds18s20 thermal sensor may send information
> about "85 degree problem" - it is read when sensor did not
> finished temerature transformation yet, how non-bus layer may know about it?

Classes. And return -EAGAIN when reading is not ready (for some reason).

>
> Your idea about classes over the various buses is good,
> but unfortunately it is utopia, al least for now,

It is not an utopia, it is Linux kernel and we do not need to get in
unfinished solution.

> so let's create w1 core layer (which, btw, is not only bus,
> which is managed by bus master dirver, but also some logic over it,
> one may call it w1 stack, stack can send such a messages, doesn't it)?
>

Heh ;) Let's concentrate on sensors stack, please...

> > >
> > > As I said I have feature requests for ability to export w1 devices
> > > outside w1 core.
> > > Probably it is due to it's private non-GPL usage, so it is not created,
> > > but it is usefull feature actually and we can not know what will
> > > happen in what context when we export master/slave devices.
> >
> > Look at your present w1_remove_master_device. It sleeps. Sop there is
> > no need for a separate thread, callers must be able to sleep anyway.
>
> That is exactly why control thread exists - to manage sleepable operations!

Read what I wrote again - if caller is sleeping on thread's completion
there is really no need for a thread. The caller can do whetever
thread does. Only if caller would send request and continue one woudl
need to set up a thread.

> > > w1 slaves can be found on the bus without search method reaction
> > > implemented in it's asic, btw.
> > > And it is _very_ usefull to add/remove slaves using external command but
> > > not using
> > > automatic detection in search methods.
> >
> > But the request for that will come from userspace with is perfectly
> > able to sleep. You are over-engineering and making kernel code
> > unnecessarily complex without thinking it through.
>
> Connector's requests come from BH context.
> Only module unloading comes with good context (in our case we do not
> get read/write operations),
> but I do not want to limit the system only for that kinds of events.
>

And you still have master's thread to manage slaves. Although I don't
quite understand why you would need manual addition of slaves. Either
they speak W1 protocol and will be added automatically, or they don't
speak w1 and then they are not w1 devices.

> > > > > I have feature requests for both adding/removing and exporting
> > > > > master devices and slaves to the external world.
> > > >
> > > > External as in userspace? It (user thread) can wait just fine...
> > >
> > > Exporting them into other kernel modules.
> > > We do not know in what context that structures will be used there.
> >
> > Why other kernel modules would be interested in raw access w1_slaves?
> > C are to give an example?
>
> Concider w1 battery slave device, which exports unified interface to
> the userspace.
> It requires access that can be obtained from different generic module
> [like existing kernelspace/userspace protocol,
> proper device files and so on],
> which will implement only read/write interface.
> It's read method will get_slave_by_something() and read it's data
> or do something else, then generic module will use that data.
>
> Generic buttery monitor will not scan w1 bus for it's devices,
> since it even does not know about w1, it only understands reading/writing
> operations.
>

And here you are thinking of classes again. Writing separate battery
monitor applets for i2c, w1, superio and the rest is not less silly.
You are trying to move them over your ocnnector code. Alternatively
you could have move them to class codes and build netlink notification
on top of them. This way you'd separate buses (physical interface)
with userpsace interfaces and allowed use of different transports.

> >
> > Wrong level. You need to start with device implementing w1_bus_master
> > (w1_bus_ops) to remova dangling data structures). Easiest way I think
> > it have the driver compiled as a module and remove it altogether - why
> > keep it if you don't need master?
>
> 1. master can be removed by command. It is not in process' context.
> Current thread can remove only all object at once, but nevertheless
> I do not want to limit it.

You are also need to remove code controlling physical device presented
as w1_master. The request will go do a different system (module).

> 2. control thread can add/remove new slaves by request.
> Usefullness of that ability was pointed in my previous e-mail,
> but you skipped that part.

I am still missing usefullness of it.

> >
> > The less code in kernel that produces data availavle elsewhere the better :)
>
> Does 3 lines of code for reading slave's names is too big
> price for not scanning the whole /sys/bus/w1/w1_master1/ directory?
>

How often do you use them? While debugging only?


> > > > > > w1-master-cleanup.patch
> > > > > > Clean-up master device implementation:
> > > > > > - get rid of separate refcount, rely on driver model to enforce
> > > > > > lifetime rules;
> > > > > > - use atomic to generate unique master IDs;
> > > > > > - drop unused fields.
> > > > >
> > > > > That patch is very broken.
> > > > > I completely against it:
> > > > > 1. it breaks process logic - searching can be interrupted and stopped,
> > > > > thread will exit on signals.
> > > >
> > > > Interrupted/stopped from userspace?
> > >
> > > Your loop waits only until interrupt happens - it can be delivered from
> > > anywhere.
> >
> > No, only root can kill kernel therad so it is pretty safe. And hey, if
> > a thread goes mad maybe it's a good thing that it can be killed.
>
> And if it exits - it breaks the logic - user can not know the state
> of the master device when thread is exited, but module was not removed
> by request.
>

I (as a root) have zillion ways to break the system. There is not hing
new. The oint that an ordinary user can't do anything with that
thread.

> >
> > device model is here to _use_ it. It already implements bunch of stuff
> > you have to re-implement if you do it "your own way" and it is already
> > debugged much better than your solution. And if there is a problem
> > with driver core implementation - well, more people are looking at it
> > and are more likely to discover a problem and offer a solution.
> >
> > I do not understand why you are against full integration with device
> > model - it does simplifies and unifies the code.
>
> Because it is not needed here - and even if it could be integrated
> more closer - your changes broke too many special design cases,
> which are not acceptible.
>

Having too many special design cases in otherwise pretty simple bus
indicates that there something wrong with the design.

> > > With such changes how to increment slave's usage counter? module_get
> > > (w1_family)?
> >
> > Actually if you need it it would be get_device(&w1_slave->dev). And if
> > you need pin family object you would get
> > get_driver(&w1_family->driver). But I don't think you will needed it.
> > Actually, at some point I had w1_family_get() implemented as a wrapper
> > to get_driver() but since it does not seem to be needed I dropped it.
>
> We can not do it in that way.
> 1. low-level bus master code differs from what w1_master is.
> 2. family itself is different from slave object.
>
> Having that we need to create w1_master/w1_family device/driver model
> locking + w1_bus_master/w1_slave locking or move them to device/driver
> model too. Why it is needed I still do not see, there is
> proper locking schema, which is broken in the places where
> existing model touches device/driver one, and it will be fixed.
>

You have exactly the same problem with master devices too. What
escapes me is the desire to have 2 separate refcounting for the same
object. Except for ability to introduce 2x more bugs.

--
Dmitry

2005-04-26 06:36:36

by Evgeniy Polyakov

[permalink] [raw]
Subject: Re: [RFC/PATCH 0/22] W1: sysfs, lifetime and other fixes

On Mon, 2005-04-25 at 15:22 -0500, Dmitry Torokhov wrote:
> On 4/25/05, Evgeniy Polyakov <[email protected]> wrote:
> > While thinking about locking schema
> > with respect to sysfs files I recalled,
> > why I implemented such a logic -
> > now one can _always_ remove _any_ module
> > [corresponding object is removed from accessible
> > pathes and waits untill all exsting users are gone],
> > which is very good - I really like it in networking model,
> > while with whole device driver model
> > if we will read device's file very quickly
> > in several threads we may end up not unloading it at all.
>
> I am sorrry, that is complete bull*. sysfs also allows removing
> modules at an arbitrary time (and usually without annoying "waiting
> for refcount" at that)... You just seem to not understand how driver
> code works, thus the need of inventing your own schema.

Ok, let's try again - now with explanation,
since it looks like you did not even try to understand what I said.
If you will remove objects from ->remove() callback
you may end up with rmmod being stuck.
Explanation: each read still gets reference counter,
while in rmmod path there is a wait until it is zero.
If there are too many simultaneous reads - even
if each will put reference counter at the end, we still can have
non zero refcnt each time we check it in rmmod path.
That is why object must be removed from accessible pathes
first, and only freed in ->remove() callback.

> BTW, I am looking at the connector code ATM and I am just amazed at
> all wied refounting stuff that is going on there. what a single
> actomic_dec_and_test() call without checkng reurn vaue is supposed to
> do again?

It has explicit barrieres, which guarantees that
there will not be atomic operation vs. non atomic
reordering.

--
Evgeniy Polyakov

Crash is better than data corruption -- Arthur Grabowski


Attachments:
signature.asc (189.00 B)
This is a digitally signed message part

2005-04-26 06:50:25

by Dmitry Torokhov

[permalink] [raw]
Subject: Re: [RFC/PATCH 0/22] W1: sysfs, lifetime and other fixes

On Tuesday 26 April 2005 01:43, Evgeniy Polyakov wrote:
> On Mon, 2005-04-25 at 15:22 -0500, Dmitry Torokhov wrote:
> > On 4/25/05, Evgeniy Polyakov <[email protected]> wrote:
> > > While thinking about locking schema
> > > with respect to sysfs files I recalled,
> > > why I implemented such a logic -
> > > now one can _always_ remove _any_ module
> > > [corresponding object is removed from accessible
> > > pathes and waits untill all exsting users are gone],
> > > which is very good - I really like it in networking model,
> > > while with whole device driver model
> > > if we will read device's file very quickly
> > > in several threads we may end up not unloading it at all.
> >
> > I am sorrry, that is complete bull*. sysfs also allows removing
> > modules at an arbitrary time (and usually without annoying "waiting
> > for refcount" at that)... You just seem to not understand how driver
> > code works, thus the need of inventing your own schema.
>
> Ok, let's try again - now with explanation,
> since it looks like you did not even try to understand what I said.
> If you will remove objects from ->remove() callback
> you may end up with rmmod being stuck.
> Explanation: each read still gets reference counter,
> while in rmmod path there is a wait until it is zero.
> If there are too many simultaneous reads - even
> if each will put reference counter at the end, we still can have
> non zero refcnt each time we check it in rmmod path.
> That is why object must be removed from accessible pathes
> first, and only freed in ->remove() callback.

Please try to read the code. device_unregister and kobject_unregister
do not require caller to wait for the last reference to drop, they rely
on availability of release method to clean up the object when last user
is gone. driver_unregister is blocking (like your family code) but
teardown takes no time. If driver is in use (attributes are open) then
module refcount is non-zero and instead of (possibly endless) "waiting for
refcount to drop" message you will get nice -EBUSY.

If you program so that you wait in module_exit for object release - you
get what you deserve.

> > BTW, I am looking at the connector code ATM and I am just amazed at
> > all wied refounting stuff that is going on there. what a single
> > actomic_dec_and_test() call without checkng reurn vaue is supposed to
> > do again?
>
> It has explicit barrieres, which guarantees that
> there will not be atomic operation vs. non atomic
> reordering.

And you can't use explicit barriers - why exactly?

--
Dmitry

2005-04-26 06:59:10

by Greg KH

[permalink] [raw]
Subject: Re: [RFC/PATCH 0/22] W1: sysfs, lifetime and other fixes

On Mon, Apr 25, 2005 at 11:32:14AM -0500, Dmitry Torokhov wrote:
> On 4/25/05, Evgeniy Polyakov <[email protected]> wrote:
> > On Thu, 2005-04-21 at 09:31 -0500, Dmitry Torokhov wrote:
> > >
> > > OK, that is what I am aying. But why do you need that attribute with
> > > variable name and a bin attribute that is not really bin but just a
> > > dump for all kind of data (looks like debug one).
> >
> > bin attribute was created for lm_sensors scripts format - it only caches
> > read value.
> > I think there might be only 2 "must have" methods - read and write.
> > I plan to implement them using connector, so probably they will go away
> > completely.
> ...
> > > You will not be able to cram all 1-wire devices into unified
> > > interface. You will need to build classes on top of it and you might
> > > use connector (I am not sure) bit not on w1 bus level.
> > > ...
> >
> > connector allows to have different objects inside one netlink group,
> > so it will use it in that way.
> > I think only two w1 methods must exist - read and write,
> > and they must follow protocol, defined in family driver.
>
> No, I think there should not be any "must have" methods on w1_bus
> level. What you really need (and this needs to be coordinated with
> other sensors people) is a "sensors" class hierarchy that will define
> classes like "temperature sensor", "fan", "vid", etc. Then your w1
> family drivers, when bound to a slave, will create needed class
> devices. i2c drivers will do the same, and your superio, and I'll be
> able to change i8k driver just for kicks. Then your usespace would not
> care what _bus_ a particular sensor is sittign on and will be
> presented with a unified interface.

Yes, that is the way to go, and is what a number of people are currently
working on implementing.

thanks,

greg k-h

2005-04-26 06:59:48

by Evgeniy Polyakov

[permalink] [raw]
Subject: Re: [RFC/PATCH 0/22] W1: sysfs, lifetime and other fixes

On Tue, 2005-04-26 at 01:50 -0500, Dmitry Torokhov wrote:
> On Tuesday 26 April 2005 01:43, Evgeniy Polyakov wrote:
> > On Mon, 2005-04-25 at 15:22 -0500, Dmitry Torokhov wrote:
> > > On 4/25/05, Evgeniy Polyakov <[email protected]> wrote:
> > > > While thinking about locking schema
> > > with respect to sysfs files I recalled,
> > > > why I implemented such a logic -
> > > > now one can _always_ remove _any_ module
> > > > [corresponding object is removed from accessible
> > > > pathes and waits untill all exsting users are gone],
> > > > which is very good - I really like it in networking model,
> > > > while with whole device driver model
> > > > if we will read device's file very quickly
> > > > in several threads we may end up not unloading it at all.
> > >
> > > I am sorrry, that is complete bull*. sysfs also allows removing
> > > modules at an arbitrary time (and usually without annoying "waiting
> > > for refcount" at that)... You just seem to not understand how driver
> > > code works, thus the need of inventing your own schema.
> >
> > Ok, let's try again - now with explanation,
> > since it looks like you did not even try to understand what I said.
> > If you will remove objects from ->remove() callback
> > you may end up with rmmod being stuck.
> > Explanation: each read still gets reference counter,
> > while in rmmod path there is a wait until it is zero.
> > If there are too many simultaneous reads - even
> > if each will put reference counter at the end, we still can have
> > non zero refcnt each time we check it in rmmod path.
> > That is why object must be removed from accessible pathes
> > first, and only freed in ->remove() callback.
>
> Please try to read the code. device_unregister and kobject_unregister
> do not require caller to wait for the last reference to drop, they rely
> on availability of release method to clean up the object when last user
> is gone. driver_unregister is blocking (like your family code) but
> teardown takes no time. If driver is in use (attributes are open) then
> module refcount is non-zero and instead of (possibly endless) "waiting for
> refcount to drop" message you will get nice -EBUSY.
>
> If you program so that you wait in module_exit for object release - you
> get what you deserve.

But we can remove objects not from rmmod path.
You pointed right example in one previous e-mail.

Using above "waiting for device..." message is for debug only.

> > > BTW, I am looking at the connector code ATM and I am just amazed at
> > > all wied refounting stuff that is going on there. what a single
> > > actomic_dec_and_test() call without checkng reurn vaue is supposed to
> > > do again?
> >
> > It has explicit barrieres, which guarantees that
> > there will not be atomic operation vs. non atomic
> > reordering.
>
> And you can't use explicit barriers - why exactly?

I used them - code was following:
smp_mb__before_atomic_dec();
atomic_dec();
smp_mb__after_atomic_dec();

I think simple atomic_dec_and_test() or even atomic_dec_and_lock()
is better.

--
Evgeniy Polyakov

Crash is better than data corruption -- Arthur Grabowski


Attachments:
signature.asc (189.00 B)
This is a digitally signed message part

2005-04-26 07:03:08

by Greg KH

[permalink] [raw]
Subject: Re: [RFC/PATCH 0/22] W1: sysfs, lifetime and other fixes

On Tue, Apr 26, 2005 at 10:43:36AM +0400, Evgeniy Polyakov wrote:
> On Mon, 2005-04-25 at 15:22 -0500, Dmitry Torokhov wrote:
> > On 4/25/05, Evgeniy Polyakov <[email protected]> wrote:
> > > While thinking about locking schema
> > > with respect to sysfs files I recalled,
> > > why I implemented such a logic -
> > > now one can _always_ remove _any_ module
> > > [corresponding object is removed from accessible
> > > pathes and waits untill all exsting users are gone],
> > > which is very good - I really like it in networking model,
> > > while with whole device driver model
> > > if we will read device's file very quickly
> > > in several threads we may end up not unloading it at all.
> >
> > I am sorrry, that is complete bull*. sysfs also allows removing
> > modules at an arbitrary time (and usually without annoying "waiting
> > for refcount" at that)... You just seem to not understand how driver
> > code works, thus the need of inventing your own schema.
>
> Ok, let's try again - now with explanation,
> since it looks like you did not even try to understand what I said.
> If you will remove objects from ->remove() callback
> you may end up with rmmod being stuck.

Yes, and that is acceptable. networking implemented their own locking
method to allow unloading of their drivers in such a manner. No other
subsystem is going to do that kind of implementation, so Dmitry is
correct here.

thanks,

greg k-h

2005-04-26 07:10:25

by Evgeniy Polyakov

[permalink] [raw]
Subject: Re: [RFC/PATCH 0/22] W1: sysfs, lifetime and other fixes

On Tue, 2005-04-26 at 00:00 -0700, Greg KH wrote:
> On Tue, Apr 26, 2005 at 10:43:36AM +0400, Evgeniy Polyakov wrote:
> > On Mon, 2005-04-25 at 15:22 -0500, Dmitry Torokhov wrote:
> > > On 4/25/05, Evgeniy Polyakov <[email protected]> wrote:
> > > > While thinking about locking schema
> > > > with respect to sysfs files I recalled,
> > > > why I implemented such a logic -
> > > > now one can _always_ remove _any_ module
> > > > [corresponding object is removed from accessible
> > > > pathes and waits untill all exsting users are gone],
> > > > which is very good - I really like it in networking model,
> > > > while with whole device driver model
> > > > if we will read device's file very quickly
> > > > in several threads we may end up not unloading it at all.
> > >
> > > I am sorrry, that is complete bull*. sysfs also allows removing
> > > modules at an arbitrary time (and usually without annoying "waiting
> > > for refcount" at that)... You just seem to not understand how driver
> > > code works, thus the need of inventing your own schema.
> >
> > Ok, let's try again - now with explanation,
> > since it looks like you did not even try to understand what I said.
> > If you will remove objects from ->remove() callback
> > you may end up with rmmod being stuck.
>
> Yes, and that is acceptable. networking implemented their own locking
> method to allow unloading of their drivers in such a manner. No other
> subsystem is going to do that kind of implementation, so Dmitry is
> correct here.

w1 does it too :)
It's locking was lurked in network code.
And it _is_ design note to be able to remove objects in any time.
Ok, I can not say, that it is exactly like networking,
since there is waiting in rmmod path, it is very similar to virtual
devices
like vlan.

> thanks,
>
> greg k-h
--
Evgeniy Polyakov

Crash is better than data corruption -- Arthur Grabowski


Attachments:
signature.asc (189.00 B)
This is a digitally signed message part

2005-04-26 07:13:47

by Evgeniy Polyakov

[permalink] [raw]
Subject: Re: [RFC/PATCH 0/22] W1: sysfs, lifetime and other fixes

On Mon, 2005-04-25 at 16:32 -0500, Dmitry Torokhov wrote:
> On 4/25/05, Evgeniy Polyakov <[email protected]> wrote:
> >
> > How do you suppose to notify about alarm condition?
> > Not from bus layer?
> > Who does send "link is down" messages? It is not the same
> > as device is present and found, it like "w1 device has something to read".
> > For example w1 ds18s20 thermal sensor may send information
> > about "85 degree problem" - it is read when sensor did not
> > finished temerature transformation yet, how non-bus layer may know about it?
>
> Classes. And return -EAGAIN when reading is not ready (for some reason).

Device may be broken, btw, and return that value always.
How to notify about such condition?

> >
> > Your idea about classes over the various buses is good,
> > but unfortunately it is utopia, al least for now,
>
> It is not an utopia, it is Linux kernel and we do not need to get in
> unfinished solution.

That will require too many changes to say:
"hey, tomorrow we will have new generic w1/i2c/superio set".
I believe it can be done, it is definitely a good idea,
but let's fix existing bugs before changing the whole tree.

> > so let's create w1 core layer (which, btw, is not only bus,
> > which is managed by bus master dirver, but also some logic over it,
> > one may call it w1 stack, stack can send such a messages, doesn't it)?
> >
>
> Heh ;) Let's concentrate on sensors stack, please...

If we still have a bugs there, I do not think it is good idea
to move things ahead.
I repeat, I agree that unufied class hierarchy for sensors devices
is a very good idea, but it can not be implemented in a couple of days,
so I would pospone it until others bugs are fixed.

> > > >
> > > > As I said I have feature requests for ability to export w1 devices
> > > > outside w1 core.
> > > > Probably it is due to it's private non-GPL usage, so it is not created,
> > > > but it is usefull feature actually and we can not know what will
> > > > happen in what context when we export master/slave devices.
> > >
> > > Look at your present w1_remove_master_device. It sleeps. Sop there is
> > > no need for a separate thread, callers must be able to sleep anyway.
> >
> > That is exactly why control thread exists - to manage sleepable operations!
>
> Read what I wrote again - if caller is sleeping on thread's completion
> there is really no need for a thread. The caller can do whetever
> thread does. Only if caller would send request and continue one woudl
> need to set up a thread.

Why do you think caller is in process context?
Control thread was created to process that work, which can not be done
in interrupt context, i.e. some command from unknown context
is deffered to control thread execution, which process it in a safe
context. Using connector for exaple you may send command REMOVE_*,
which will be received in BH context and just set the flag, which
will be seen by control thread.

> > > > w1 slaves can be found on the bus without search method reaction
> > > > implemented in it's asic, btw.
> > > > And it is _very_ usefull to add/remove slaves using external command but
> > > > not using
> > > > automatic detection in search methods.
> > >
> > > But the request for that will come from userspace with is perfectly
> > > able to sleep. You are over-engineering and making kernel code
> > > unnecessarily complex without thinking it through.
> >
> > Connector's requests come from BH context.
> > Only module unloading comes with good context (in our case we do not
> > get read/write operations),
> > but I do not want to limit the system only for that kinds of events.
> >
>
> And you still have master's thread to manage slaves. Although I don't
> quite understand why you would need manual addition of slaves. Either
> they speak W1 protocol and will be added automatically, or they don't
> speak w1 and then they are not w1 devices.

There are w1 devices that do not respond to search command
[actually there are devices that understand only one command at all],
ok, they are broken, but it does not matter.

> > > > > > I have feature requests for both adding/removing and exporting
> > > > > > master devices and slaves to the external world.
> > > > >
> > > > > External as in userspace? It (user thread) can wait just fine...
> > > >
> > > > Exporting them into other kernel modules.
> > > > We do not know in what context that structures will be used there.
> > >
> > > Why other kernel modules would be interested in raw access w1_slaves?
> > > C are to give an example?
> >
> > Concider w1 battery slave device, which exports unified interface to
> > the userspace.
> > It requires access that can be obtained from different generic module
> > [like existing kernelspace/userspace protocol,
> > proper device files and so on],
> > which will implement only read/write interface.
> > It's read method will get_slave_by_something() and read it's data
> > or do something else, then generic module will use that data.
> >
> > Generic buttery monitor will not scan w1 bus for it's devices,
> > since it even does not know about w1, it only understands reading/writing
> > operations.
> >
>
> And here you are thinking of classes again. Writing separate battery
> monitor applets for i2c, w1, superio and the rest is not less silly.
> You are trying to move them over your ocnnector code. Alternatively
> you could have move them to class codes and build netlink notification
> on top of them. This way you'd separate buses (physical interface)
> with userpsace interfaces and allowed use of different transports.

No, connector is just an example.

Classes hierarchy for all sensor devices is good idea,
but not too easy to be implemeted.
I stronly agree with it and would like to port w1 to it.

Connector could be used to control that classes - just an example.

> > >
> > > Wrong level. You need to start with device implementing w1_bus_master
> > > (w1_bus_ops) to remova dangling data structures). Easiest way I think
> > > it have the driver compiled as a module and remove it altogether - why
> > > keep it if you don't need master?
> >
> > 1. master can be removed by command. It is not in process' context.
> > Current thread can remove only all object at once, but nevertheless
> > I do not want to limit it.
>
> You are also need to remove code controlling physical device presented
> as w1_master. The request will go do a different system (module).

No need to remove bus master device, it can be there with zero refcnt,
so when it will call w1_remove_master_device() it wouldn't block.

> > 2. control thread can add/remove new slaves by request.
> > Usefullness of that ability was pointed in my previous e-mail,
> > but you skipped that part.
>
> I am still missing usefullness of it.

There are devices that can not be found using w1 search commands,
there are devices that only understand one command,
I agree they are broken, but they still can be easily supported
by w1 subsystem.

> > >
> > > The less code in kernel that produces data availavle elsewhere the better :)
> >
> > Does 3 lines of code for reading slave's names is too big
> > price for not scanning the whole /sys/bus/w1/w1_master1/ directory?
> >
>
> How often do you use them? While debugging only?

Always.
With long line it is very common to lose w1 slaves - that is why it was
TTL
attribute created - it's purpose is to integrate such events.
With device like iButton it _IS_ thy _only_ behaviour - slave object
exists only couple of seconds.

>
> > > > > > > w1-master-cleanup.patch
> > > > > > > Clean-up master device implementation:
> > > > > > > - get rid of separate refcount, rely on driver model to enforce
> > > > > > > lifetime rules;
> > > > > > > - use atomic to generate unique master IDs;
> > > > > > > - drop unused fields.
> > > > > >
> > > > > > That patch is very broken.
> > > > > > I completely against it:
> > > > > > 1. it breaks process logic - searching can be interrupted and stopped,
> > > > > > thread will exit on signals.
> > > > >
> > > > > Interrupted/stopped from userspace?
> > > >
> > > > Your loop waits only until interrupt happens - it can be delivered from
> > > > anywhere.
> > >
> > > No, only root can kill kernel therad so it is pretty safe. And hey, if
> > > a thread goes mad maybe it's a good thing that it can be killed.
> >
> > And if it exits - it breaks the logic - user can not know the state
> > of the master device when thread is exited, but module was not removed
> > by request.
> >
>
> I (as a root) have zillion ways to break the system. There is not hing
> new. The oint that an ordinary user can't do anything with that
> thread.

Signal can be sent not only by your request.

> > >
> > > device model is here to _use_ it. It already implements bunch of stuff
> > > you have to re-implement if you do it "your own way" and it is already
> > > debugged much better than your solution. And if there is a problem
> > > with driver core implementation - well, more people are looking at it
> > > and are more likely to discover a problem and offer a solution.
> > >
> > > I do not understand why you are against full integration with device
> > > model - it does simplifies and unifies the code.
> >
> > Because it is not needed here - and even if it could be integrated
> > more closer - your changes broke too many special design cases,
> > which are not acceptible.
> >
>
> Having too many special design cases in otherwise pretty simple bus
> indicates that there something wrong with the design.

I see your point.

> > > > With such changes how to increment slave's usage counter? module_get
> > > > (w1_family)?
> > >
> > > Actually if you need it it would be get_device(&w1_slave->dev). And if
> > > you need pin family object you would get
> > > get_driver(&w1_family->driver). But I don't think you will needed it.
> > > Actually, at some point I had w1_family_get() implemented as a wrapper
> > > to get_driver() but since it does not seem to be needed I dropped it.
> >
> > We can not do it in that way.
> > 1. low-level bus master code differs from what w1_master is.
> > 2. family itself is different from slave object.
> >
> > Having that we need to create w1_master/w1_family device/driver model
> > locking + w1_bus_master/w1_slave locking or move them to device/driver
> > model too. Why it is needed I still do not see, there is
> > proper locking schema, which is broken in the places where
> > existing model touches device/driver one, and it will be fixed.
> >
>
> You have exactly the same problem with master devices too. What
> escapes me is the desire to have 2 separate refcounting for the same
> object. Except for ability to introduce 2x more bugs.

Yep.
As I said in previous e-mail - I do want to remove objects in any time,
so it has it's own locking schema, but I also do want to use sysfs
objects, so there is another locking schema - in the place they are
touch each other there is a problem and I will fix it,
probably by moving object freeing into ->remove() callback.

--
Evgeniy Polyakov

Crash is better than data corruption -- Arthur Grabowski


Attachments:
signature.asc (189.00 B)
This is a digitally signed message part

2005-04-26 07:19:12

by Dmitry Torokhov

[permalink] [raw]
Subject: Re: [RFC/PATCH 0/22] W1: sysfs, lifetime and other fixes

On Tuesday 26 April 2005 02:06, Evgeniy Polyakov wrote:
> On Tue, 2005-04-26 at 01:50 -0500, Dmitry Torokhov wrote:
> >
> > If you program so that you wait in module_exit for object release - you
> > get what you deserve.
>
> But we can remove objects not from rmmod path.
> You pointed right example in one previous e-mail.

Right, and you need to be careful so that thread does not hold any references
to the resource it tries to free. rmmod is just one pf the common examples.
But you need to consider this scenario whether you using driver model or your
separate refcount - the basic problem is still the same.

> Using above "waiting for device..." message is for debug only.
>
> > > > BTW, I am looking at the connector code ATM and I am just amazed at
> > > > all wied refounting stuff that is going on there. what a single
> > > > actomic_dec_and_test() call without checkng reurn vaue is supposed to
> > > > do again?
> > >
> > > It has explicit barrieres, which guarantees that
> > > there will not be atomic operation vs. non atomic
> > > reordering.
> >
> > And you can't use explicit barriers - why exactly?
>
> I used them - code was following:
> smp_mb__before_atomic_dec();
> atomic_dec();
> smp_mb__after_atomic_dec();
>
> I think simple atomic_dec_and_test() or even atomic_dec_and_lock()
> is better.

This is usually indicates that there some kiond of a problem. Consider
following fragment:

> +static void cn_queue_wrapper(void *data)
> +{
> +       struct cn_callback_entry *cbq = (struct cn_callback_entry *)data;
> +
> +       atomic_inc_and_test(&cbq->cb->refcnt);
> +       cbq->cb->callback(cbq->cb->priv);
> +       atomic_dec_and_test(&cbq->cb->refcnt);
>

What exactly this refcount protects? Can it be that other code decrements
refcount and frees the object right when one CPU is entering this function?
If not that means that cb structure is protected by some other means, so
why we need to increment refcout here and consider ordering?

Btw, cb refcount can be complelely removed, something like the patch below
(won't apply cleanly as I have some other stuff).

--
Dmitry

drivers/connector/cn_queue.c | 85 +++++++++++--------------------------------
include/linux/connector.h | 2 -
2 files changed, 23 insertions(+), 64 deletions(-)

Index: linux-2.6.11/drivers/connector/cn_queue.c
===================================================================
--- linux-2.6.11.orig/drivers/connector/cn_queue.c
+++ linux-2.6.11/drivers/connector/cn_queue.c
@@ -33,49 +33,12 @@

static void cn_queue_wrapper(void *data)
{
- struct cn_callback_entry *cbq = (struct cn_callback_entry *)data;
+ struct cn_callback_entry *cbq = data;

- atomic_inc_and_test(&cbq->cb->refcnt);
cbq->cb->callback(cbq->cb->priv);
- atomic_dec_and_test(&cbq->cb->refcnt);
-
cbq->destruct_data(cbq->ddata);
}

-static struct cn_callback_entry *cn_queue_alloc_callback_entry(struct cn_callback *cb)
-{
- struct cn_callback_entry *cbq;
-
- cbq = kmalloc(sizeof(*cbq), GFP_KERNEL);
- if (!cbq) {
- printk(KERN_ERR "Failed to create new callback queue.\n");
- return NULL;
- }
-
- memset(cbq, 0, sizeof(*cbq));
-
- cbq->cb = cb;
-
- INIT_WORK(&cbq->work, &cn_queue_wrapper, cbq);
-
- return cbq;
-}
-
-static void cn_queue_free_callback(struct cn_callback_entry *cbq)
-{
- cancel_delayed_work(&cbq->work);
- flush_workqueue(cbq->pdev->cn_queue);
-
- while (atomic_read(&cbq->cb->refcnt)) {
- printk(KERN_INFO "Waiting for %s to become free: refcnt=%d.\n",
- cbq->pdev->name, atomic_read(&cbq->cb->refcnt));
-
- msleep(1000);
- }
-
- kfree(cbq);
-}
-
int cn_cb_equal(struct cb_id *i1, struct cb_id *i2)
{
#if 0
@@ -90,40 +53,37 @@ int cn_cb_equal(struct cb_id *i1, struct
int cn_queue_add_callback(struct cn_queue_dev *dev, struct cn_callback *cb)
{
struct cn_callback_entry *cbq, *__cbq;
- int found = 0;
+ int retval = 0;

- cbq = cn_queue_alloc_callback_entry(cb);
- if (!cbq)
+ cbq = kmalloc(sizeof(*cbq), GFP_KERNEL);
+ if (!cbq) {
+ printk(KERN_ERR "Failed to create new callback queue.\n");
return -ENOMEM;
+ }

atomic_inc(&dev->refcnt);
+
+ memset(cbq, 0, sizeof(*cbq));
+ INIT_WORK(&cbq->work, &cn_queue_wrapper, cbq);
+ cbq->cb = cb;
cbq->pdev = dev;
+ cbq->nls = dev->nls;
+ cbq->seq = 0;
+ cbq->group = cbq->cb->id.idx;

spin_lock_bh(&dev->queue_lock);
+
list_for_each_entry(__cbq, &dev->queue_list, callback_entry) {
if (cn_cb_equal(&__cbq->cb->id, &cb->id)) {
- found = 1;
- break;
+ retval = -EEXIST;
+ kfree(cbq);
+ goto out;
}
}
- if (!found) {
- atomic_set(&cbq->cb->refcnt, 1);
- list_add_tail(&cbq->callback_entry, &dev->queue_list);
- }
+ list_add_tail(&cbq->callback_entry, &dev->queue_list);
+ out:
spin_unlock_bh(&dev->queue_lock);
-
- if (found) {
- atomic_dec(&dev->refcnt);
- atomic_set(&cbq->cb->refcnt, 0);
- cn_queue_free_callback(cbq);
- return -EINVAL;
- }
-
- cbq->nls = dev->nls;
- cbq->seq = 0;
- cbq->group = cbq->cb->id.idx;
-
- return 0;
+ return retval;
}

void cn_queue_del_callback(struct cn_queue_dev *dev, struct cb_id *id)
@@ -142,8 +102,9 @@ void cn_queue_del_callback(struct cn_que
spin_unlock_bh(&dev->queue_lock);

if (found) {
- atomic_dec(&cbq->cb->refcnt);
- cn_queue_free_callback(cbq);
+ cancel_delayed_work(&cbq->work);
+ flush_workqueue(cbq->pdev->cn_queue);
+ kfree(cbq);
atomic_dec_and_test(&dev->refcnt);
}
}
Index: linux-2.6.11/include/linux/connector.h
===================================================================
--- linux-2.6.11.orig/include/linux/connector.h
+++ linux-2.6.11/include/linux/connector.h
@@ -115,8 +115,6 @@ struct cn_callback
struct cb_id id;
void (* callback)(void *);
void *priv;
-
- atomic_t refcnt;
};

struct cn_callback_entry

2005-04-26 07:28:26

by Evgeniy Polyakov

[permalink] [raw]
Subject: Re: [RFC/PATCH 0/22] W1: sysfs, lifetime and other fixes

On Tue, 2005-04-26 at 02:16 -0500, Dmitry Torokhov wrote:

> > > > It has explicit barrieres, which guarantees that
> > > > there will not be atomic operation vs. non atomic
> > > > reordering.
> > >
> > > And you can't use explicit barriers - why exactly?
> >
> > I used them - code was following:
> > smp_mb__before_atomic_dec();
> > atomic_dec();
> > smp_mb__after_atomic_dec();
> >
> > I think simple atomic_dec_and_test() or even atomic_dec_and_lock()
> > is better.
>
> This is usually indicates that there some kiond of a problem. Consider
> following fragment:
>
> > +static void cn_queue_wrapper(void *data)
> > +{
> > + struct cn_callback_entry *cbq = (struct cn_callback_entry *)data;
> > +
> > + atomic_inc_and_test(&cbq->cb->refcnt);
> > + cbq->cb->callback(cbq->cb->priv);
> > + atomic_dec_and_test(&cbq->cb->refcnt);
> >
>
> What exactly this refcount protects? Can it be that other code decrements
> refcount and frees the object right when one CPU is entering this function?
> If not that means that cb structure is protected by some other means, so
> why we need to increment refcout here and consider ordering?

It does not needed there. I pointed it to Andrew when we discuss it
couple of weeks ago, but forget to remove.

> Btw, cb refcount can be complelely removed, something like the patch below
> (won't apply cleanly as I have some other stuff).

I will think of it some more, probably you are right,
it looks like flush_workqueue() is sufficient for that.

> --
> Dmitry
>
> drivers/connector/cn_queue.c | 85 +++++++++++--------------------------------
> include/linux/connector.h | 2 -
> 2 files changed, 23 insertions(+), 64 deletions(-)
>
> Index: linux-2.6.11/drivers/connector/cn_queue.c
> ===================================================================
> --- linux-2.6.11.orig/drivers/connector/cn_queue.c
> +++ linux-2.6.11/drivers/connector/cn_queue.c
> @@ -33,49 +33,12 @@
>
> static void cn_queue_wrapper(void *data)
> {
> - struct cn_callback_entry *cbq = (struct cn_callback_entry *)data;
> + struct cn_callback_entry *cbq = data;
>
> - atomic_inc_and_test(&cbq->cb->refcnt);
> cbq->cb->callback(cbq->cb->priv);
> - atomic_dec_and_test(&cbq->cb->refcnt);
> -
> cbq->destruct_data(cbq->ddata);
> }
>
> -static struct cn_callback_entry *cn_queue_alloc_callback_entry(struct cn_callback *cb)
> -{
> - struct cn_callback_entry *cbq;
> -
> - cbq = kmalloc(sizeof(*cbq), GFP_KERNEL);
> - if (!cbq) {
> - printk(KERN_ERR "Failed to create new callback queue.\n");
> - return NULL;
> - }
> -
> - memset(cbq, 0, sizeof(*cbq));
> -
> - cbq->cb = cb;
> -
> - INIT_WORK(&cbq->work, &cn_queue_wrapper, cbq);
> -
> - return cbq;
> -}
> -
> -static void cn_queue_free_callback(struct cn_callback_entry *cbq)
> -{
> - cancel_delayed_work(&cbq->work);
> - flush_workqueue(cbq->pdev->cn_queue);
> -
> - while (atomic_read(&cbq->cb->refcnt)) {
> - printk(KERN_INFO "Waiting for %s to become free: refcnt=%d.\n",
> - cbq->pdev->name, atomic_read(&cbq->cb->refcnt));
> -
> - msleep(1000);
> - }
> -
> - kfree(cbq);
> -}
> -
> int cn_cb_equal(struct cb_id *i1, struct cb_id *i2)
> {
> #if 0
> @@ -90,40 +53,37 @@ int cn_cb_equal(struct cb_id *i1, struct
> int cn_queue_add_callback(struct cn_queue_dev *dev, struct cn_callback *cb)
> {
> struct cn_callback_entry *cbq, *__cbq;
> - int found = 0;
> + int retval = 0;
>
> - cbq = cn_queue_alloc_callback_entry(cb);
> - if (!cbq)
> + cbq = kmalloc(sizeof(*cbq), GFP_KERNEL);
> + if (!cbq) {
> + printk(KERN_ERR "Failed to create new callback queue.\n");
> return -ENOMEM;
> + }
>
> atomic_inc(&dev->refcnt);
> +
> + memset(cbq, 0, sizeof(*cbq));
> + INIT_WORK(&cbq->work, &cn_queue_wrapper, cbq);
> + cbq->cb = cb;
> cbq->pdev = dev;
> + cbq->nls = dev->nls;
> + cbq->seq = 0;
> + cbq->group = cbq->cb->id.idx;
>
> spin_lock_bh(&dev->queue_lock);
> +
> list_for_each_entry(__cbq, &dev->queue_list, callback_entry) {
> if (cn_cb_equal(&__cbq->cb->id, &cb->id)) {
> - found = 1;
> - break;
> + retval = -EEXIST;
> + kfree(cbq);
> + goto out;
> }
> }
> - if (!found) {
> - atomic_set(&cbq->cb->refcnt, 1);
> - list_add_tail(&cbq->callback_entry, &dev->queue_list);
> - }
> + list_add_tail(&cbq->callback_entry, &dev->queue_list);
> + out:
> spin_unlock_bh(&dev->queue_lock);
> -
> - if (found) {
> - atomic_dec(&dev->refcnt);
> - atomic_set(&cbq->cb->refcnt, 0);
> - cn_queue_free_callback(cbq);
> - return -EINVAL;
> - }
> -
> - cbq->nls = dev->nls;
> - cbq->seq = 0;
> - cbq->group = cbq->cb->id.idx;
> -
> - return 0;
> + return retval;
> }
>
> void cn_queue_del_callback(struct cn_queue_dev *dev, struct cb_id *id)
> @@ -142,8 +102,9 @@ void cn_queue_del_callback(struct cn_que
> spin_unlock_bh(&dev->queue_lock);
>
> if (found) {
> - atomic_dec(&cbq->cb->refcnt);
> - cn_queue_free_callback(cbq);
> + cancel_delayed_work(&cbq->work);
> + flush_workqueue(cbq->pdev->cn_queue);
> + kfree(cbq);
> atomic_dec_and_test(&dev->refcnt);
> }
> }
> Index: linux-2.6.11/include/linux/connector.h
> ===================================================================
> --- linux-2.6.11.orig/include/linux/connector.h
> +++ linux-2.6.11/include/linux/connector.h
> @@ -115,8 +115,6 @@ struct cn_callback
> struct cb_id id;
> void (* callback)(void *);
> void *priv;
> -
> - atomic_t refcnt;
> };
>
> struct cn_callback_entry
--
Evgeniy Polyakov

Crash is better than data corruption -- Arthur Grabowski


Attachments:
signature.asc (189.00 B)
This is a digitally signed message part