diff options
-rw-r--r-- | Documentation/w1/w1.netlink | 98 | ||||
-rw-r--r-- | drivers/w1/Makefile | 2 | ||||
-rw-r--r-- | drivers/w1/slaves/w1_ds2433.c | 1 | ||||
-rw-r--r-- | drivers/w1/slaves/w1_smem.c | 1 | ||||
-rw-r--r-- | drivers/w1/slaves/w1_therm.c | 1 | ||||
-rw-r--r-- | drivers/w1/w1.c | 137 | ||||
-rw-r--r-- | drivers/w1/w1.h | 38 | ||||
-rw-r--r-- | drivers/w1/w1_family.h | 1 | ||||
-rw-r--r-- | drivers/w1/w1_int.c | 27 | ||||
-rw-r--r-- | drivers/w1/w1_io.c | 18 | ||||
-rw-r--r-- | drivers/w1/w1_netlink.c | 215 | ||||
-rw-r--r-- | drivers/w1/w1_netlink.h | 38 |
12 files changed, 445 insertions, 132 deletions
diff --git a/Documentation/w1/w1.netlink b/Documentation/w1/w1.netlink new file mode 100644 index 000000000000..3640c7c87d45 --- /dev/null +++ b/Documentation/w1/w1.netlink | |||
@@ -0,0 +1,98 @@ | |||
1 | Userspace communication protocol over connector [1]. | ||
2 | |||
3 | |||
4 | Message types. | ||
5 | ============= | ||
6 | |||
7 | There are three types of messages between w1 core and userspace: | ||
8 | 1. Events. They are generated each time new master or slave device found | ||
9 | either due to automatic or requested search. | ||
10 | 2. Userspace commands. Includes read/write and search/alarm search comamnds. | ||
11 | 3. Replies to userspace commands. | ||
12 | |||
13 | |||
14 | Protocol. | ||
15 | ======== | ||
16 | |||
17 | [struct cn_msg] - connector header. It's length field is equal to size of the attached data. | ||
18 | [struct w1_netlink_msg] - w1 netlink header. | ||
19 | __u8 type - message type. | ||
20 | W1_SLAVE_ADD/W1_SLAVE_REMOVE - slave add/remove events. | ||
21 | W1_MASTER_ADD/W1_MASTER_REMOVE - master add/remove events. | ||
22 | W1_MASTER_CMD - userspace command for bus master device (search/alarm search). | ||
23 | W1_SLAVE_CMD - userspace command for slave device (read/write/ search/alarm search | ||
24 | for bus master device where given slave device found). | ||
25 | __u8 res - reserved | ||
26 | __u16 len - size of attached to this header data. | ||
27 | union { | ||
28 | __u8 id; - slave unique device id | ||
29 | struct w1_mst { | ||
30 | __u32 id; - master's id. | ||
31 | __u32 res; - reserved | ||
32 | } mst; | ||
33 | } id; | ||
34 | |||
35 | [strucrt w1_netlink_cmd] - command for gived master or slave device. | ||
36 | __u8 cmd - command opcode. | ||
37 | W1_CMD_READ - read command. | ||
38 | W1_CMD_WRITE - write command. | ||
39 | W1_CMD_SEARCH - search command. | ||
40 | W1_CMD_ALARM_SEARCH - alarm search command. | ||
41 | __u8 res - reserved | ||
42 | __u16 len - length of data for this command. | ||
43 | For read command data must be allocated like for write command. | ||
44 | __u8 data[0] - data for this command. | ||
45 | |||
46 | |||
47 | Each connector message can include one or more w1_netlink_msg with zero of more attached w1_netlink_cmd messages. | ||
48 | |||
49 | For event messages there are no w1_netlink_cmd embedded structures, only connector header | ||
50 | and w1_netlink_msg strucutre with "len" field being zero and filled type (one of event types) | ||
51 | and id - either 8 bytes of slave unique id in host order, or master's id, which is assigned | ||
52 | to bus master device when it is added to w1 core. | ||
53 | |||
54 | Currently replies to userspace commands are only generated for read command request. | ||
55 | One reply is generated exactly for one w1_netlink_cmd read request. | ||
56 | Replies are not combined when sent - i.e. typical reply messages looks like the following: | ||
57 | [cn_msg][w1_netlink_msg][w1_netlink_cmd] | ||
58 | cn_msg.len = sizeof(struct w1_netlink_msg) + sizeof(struct w1_netlink_cmd) + cmd->len; | ||
59 | w1_netlink_msg.len = sizeof(struct w1_netlink_cmd) + cmd->len; | ||
60 | w1_netlink_cmd.len = cmd->len; | ||
61 | |||
62 | |||
63 | Operation steps in w1 core when new command is received. | ||
64 | ======================================================= | ||
65 | |||
66 | When new message (w1_netlink_msg) is received w1 core detects if it is master of slave request, | ||
67 | according to w1_netlink_msg.type field. | ||
68 | Then master or slave device is searched for. | ||
69 | When found, master device (requested or those one on where slave device is found) is locked. | ||
70 | If slave command is requested, then reset/select procedure is started to select given device. | ||
71 | |||
72 | Then all requested in w1_netlink_msg operations are performed one by one. | ||
73 | If command requires reply (like read command) it is sent on command completion. | ||
74 | |||
75 | When all commands (w1_netlink_cmd) are processed muster device is unlocked | ||
76 | and next w1_netlink_msg header processing started. | ||
77 | |||
78 | |||
79 | Connector [1] specific documentation. | ||
80 | ==================================== | ||
81 | |||
82 | Each connector message includes two u32 fields as "address". | ||
83 | w1 uses CN_W1_IDX and CN_W1_VAL defined in include/linux/connector.h header. | ||
84 | Each message also includes sequence and acknowledge numbers. | ||
85 | Sequence number for event messages is appropriate bus master sequence number increased with | ||
86 | each event message sent "through" this master. | ||
87 | Sequence number for userspace requests is set by userspace application. | ||
88 | Sequence number for reply is the same as was in request, and | ||
89 | acknowledge number is set to seq+1. | ||
90 | |||
91 | |||
92 | Additional documantion, source code examples. | ||
93 | ============================================ | ||
94 | |||
95 | 1. Documentation/connector | ||
96 | 2. http://tservice.net.ru/~s0mbre/archive/w1 | ||
97 | This archive includes userspace application w1d.c which | ||
98 | uses read/write/search commands for all master/slave devices found on the bus. | ||
diff --git a/drivers/w1/Makefile b/drivers/w1/Makefile index 0c2aa22d8c04..f0465c20a675 100644 --- a/drivers/w1/Makefile +++ b/drivers/w1/Makefile | |||
@@ -2,7 +2,7 @@ | |||
2 | # Makefile for the Dallas's 1-wire bus. | 2 | # Makefile for the Dallas's 1-wire bus. |
3 | # | 3 | # |
4 | 4 | ||
5 | ifneq ($(CONFIG_NET), y) | 5 | ifeq ($(CONFIG_CONNECTOR), n) |
6 | EXTRA_CFLAGS += -DNETLINK_DISABLED | 6 | EXTRA_CFLAGS += -DNETLINK_DISABLED |
7 | endif | 7 | endif |
8 | 8 | ||
diff --git a/drivers/w1/slaves/w1_ds2433.c b/drivers/w1/slaves/w1_ds2433.c index fb118be789ea..ddd01e6fc2c9 100644 --- a/drivers/w1/slaves/w1_ds2433.c +++ b/drivers/w1/slaves/w1_ds2433.c | |||
@@ -22,7 +22,6 @@ | |||
22 | #endif | 22 | #endif |
23 | 23 | ||
24 | #include "../w1.h" | 24 | #include "../w1.h" |
25 | #include "../w1_io.h" | ||
26 | #include "../w1_int.h" | 25 | #include "../w1_int.h" |
27 | #include "../w1_family.h" | 26 | #include "../w1_family.h" |
28 | 27 | ||
diff --git a/drivers/w1/slaves/w1_smem.c b/drivers/w1/slaves/w1_smem.c index c6d3be54f94c..cc8c02e92593 100644 --- a/drivers/w1/slaves/w1_smem.c +++ b/drivers/w1/slaves/w1_smem.c | |||
@@ -28,7 +28,6 @@ | |||
28 | #include <linux/types.h> | 28 | #include <linux/types.h> |
29 | 29 | ||
30 | #include "../w1.h" | 30 | #include "../w1.h" |
31 | #include "../w1_io.h" | ||
32 | #include "../w1_int.h" | 31 | #include "../w1_int.h" |
33 | #include "../w1_family.h" | 32 | #include "../w1_family.h" |
34 | 33 | ||
diff --git a/drivers/w1/slaves/w1_therm.c b/drivers/w1/slaves/w1_therm.c index 536d16d78de7..44afdffe3c8b 100644 --- a/drivers/w1/slaves/w1_therm.c +++ b/drivers/w1/slaves/w1_therm.c | |||
@@ -29,7 +29,6 @@ | |||
29 | #include <linux/delay.h> | 29 | #include <linux/delay.h> |
30 | 30 | ||
31 | #include "../w1.h" | 31 | #include "../w1.h" |
32 | #include "../w1_io.h" | ||
33 | #include "../w1_int.h" | 32 | #include "../w1_int.h" |
34 | #include "../w1_family.h" | 33 | #include "../w1_family.h" |
35 | 34 | ||
diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c index c9486c168505..32d8de881f11 100644 --- a/drivers/w1/w1.c +++ b/drivers/w1/w1.c | |||
@@ -35,7 +35,6 @@ | |||
35 | #include <asm/atomic.h> | 35 | #include <asm/atomic.h> |
36 | 36 | ||
37 | #include "w1.h" | 37 | #include "w1.h" |
38 | #include "w1_io.h" | ||
39 | #include "w1_log.h" | 38 | #include "w1_log.h" |
40 | #include "w1_int.h" | 39 | #include "w1_int.h" |
41 | #include "w1_family.h" | 40 | #include "w1_family.h" |
@@ -55,7 +54,7 @@ module_param_named(control_timeout, w1_control_timeout, int, 0); | |||
55 | module_param_named(max_slave_count, w1_max_slave_count, int, 0); | 54 | module_param_named(max_slave_count, w1_max_slave_count, int, 0); |
56 | module_param_named(slave_ttl, w1_max_slave_ttl, int, 0); | 55 | module_param_named(slave_ttl, w1_max_slave_ttl, int, 0); |
57 | 56 | ||
58 | DEFINE_SPINLOCK(w1_mlock); | 57 | DECLARE_MUTEX(w1_mlock); |
59 | LIST_HEAD(w1_masters); | 58 | LIST_HEAD(w1_masters); |
60 | 59 | ||
61 | static struct task_struct *w1_control_thread; | 60 | static struct task_struct *w1_control_thread; |
@@ -75,8 +74,6 @@ static void w1_master_release(struct device *dev) | |||
75 | struct w1_master *md = dev_to_w1_master(dev); | 74 | struct w1_master *md = dev_to_w1_master(dev); |
76 | 75 | ||
77 | dev_dbg(dev, "%s: Releasing %s.\n", __func__, md->name); | 76 | dev_dbg(dev, "%s: Releasing %s.\n", __func__, md->name); |
78 | |||
79 | dev_fini_netlink(md); | ||
80 | memset(md, 0, sizeof(struct w1_master) + sizeof(struct w1_bus_master)); | 77 | memset(md, 0, sizeof(struct w1_master) + sizeof(struct w1_bus_master)); |
81 | kfree(md); | 78 | kfree(md); |
82 | } | 79 | } |
@@ -85,10 +82,10 @@ static void w1_slave_release(struct device *dev) | |||
85 | { | 82 | { |
86 | struct w1_slave *sl = dev_to_w1_slave(dev); | 83 | struct w1_slave *sl = dev_to_w1_slave(dev); |
87 | 84 | ||
88 | dev_dbg(dev, "%s: Releasing %s.\n", __func__, sl->name); | 85 | printk("%s: Releasing %s.\n", __func__, sl->name); |
89 | 86 | ||
90 | while (atomic_read(&sl->refcnt)) { | 87 | while (atomic_read(&sl->refcnt)) { |
91 | dev_dbg(dev, "Waiting for %s to become free: refcnt=%d.\n", | 88 | printk("Waiting for %s to become free: refcnt=%d.\n", |
92 | sl->name, atomic_read(&sl->refcnt)); | 89 | sl->name, atomic_read(&sl->refcnt)); |
93 | if (msleep_interruptible(1000)) | 90 | if (msleep_interruptible(1000)) |
94 | flush_signals(current); | 91 | flush_signals(current); |
@@ -111,7 +108,6 @@ static ssize_t w1_slave_read_id(struct kobject *kobj, char *buf, loff_t off, siz | |||
111 | { | 108 | { |
112 | struct w1_slave *sl = kobj_to_w1_slave(kobj); | 109 | struct w1_slave *sl = kobj_to_w1_slave(kobj); |
113 | 110 | ||
114 | atomic_inc(&sl->refcnt); | ||
115 | if (off > 8) { | 111 | if (off > 8) { |
116 | count = 0; | 112 | count = 0; |
117 | } else { | 113 | } else { |
@@ -120,7 +116,6 @@ static ssize_t w1_slave_read_id(struct kobject *kobj, char *buf, loff_t off, siz | |||
120 | 116 | ||
121 | memcpy(buf, (u8 *)&sl->reg_num, count); | 117 | memcpy(buf, (u8 *)&sl->reg_num, count); |
122 | } | 118 | } |
123 | atomic_dec(&sl->refcnt); | ||
124 | 119 | ||
125 | return count; | 120 | return count; |
126 | } | 121 | } |
@@ -230,12 +225,11 @@ struct device w1_master_device = { | |||
230 | .release = &w1_master_release | 225 | .release = &w1_master_release |
231 | }; | 226 | }; |
232 | 227 | ||
233 | static struct device_driver w1_slave_driver = { | 228 | struct device_driver w1_slave_driver = { |
234 | .name = "w1_slave_driver", | 229 | .name = "w1_slave_driver", |
235 | .bus = &w1_bus_type, | 230 | .bus = &w1_bus_type, |
236 | }; | 231 | }; |
237 | 232 | ||
238 | #if 0 | ||
239 | struct device w1_slave_device = { | 233 | struct device w1_slave_device = { |
240 | .parent = NULL, | 234 | .parent = NULL, |
241 | .bus = &w1_bus_type, | 235 | .bus = &w1_bus_type, |
@@ -243,7 +237,6 @@ struct device w1_slave_device = { | |||
243 | .driver = &w1_slave_driver, | 237 | .driver = &w1_slave_driver, |
244 | .release = &w1_slave_release | 238 | .release = &w1_slave_release |
245 | }; | 239 | }; |
246 | #endif /* 0 */ | ||
247 | 240 | ||
248 | static ssize_t w1_master_attribute_show_name(struct device *dev, struct device_attribute *attr, char *buf) | 241 | static ssize_t w1_master_attribute_show_name(struct device *dev, struct device_attribute *attr, char *buf) |
249 | { | 242 | { |
@@ -423,7 +416,7 @@ int w1_create_master_attributes(struct w1_master *master) | |||
423 | return sysfs_create_group(&master->dev.kobj, &w1_master_defattr_group); | 416 | return sysfs_create_group(&master->dev.kobj, &w1_master_defattr_group); |
424 | } | 417 | } |
425 | 418 | ||
426 | static void w1_destroy_master_attributes(struct w1_master *master) | 419 | void w1_destroy_master_attributes(struct w1_master *master) |
427 | { | 420 | { |
428 | sysfs_remove_group(&master->dev.kobj, &w1_master_defattr_group); | 421 | sysfs_remove_group(&master->dev.kobj, &w1_master_defattr_group); |
429 | } | 422 | } |
@@ -454,14 +447,11 @@ static int w1_uevent(struct device *dev, char **envp, int num_envp, char *buffer | |||
454 | if (dev->driver != &w1_slave_driver || !sl) | 447 | if (dev->driver != &w1_slave_driver || !sl) |
455 | return 0; | 448 | return 0; |
456 | 449 | ||
457 | err = add_uevent_var(envp, num_envp, &cur_index, buffer, buffer_size, | 450 | err = add_uevent_var(envp, num_envp, &cur_index, buffer, buffer_size, &cur_len, "W1_FID=%02X", sl->reg_num.family); |
458 | &cur_len, "W1_FID=%02X", sl->reg_num.family); | ||
459 | if (err) | 451 | if (err) |
460 | return err; | 452 | return err; |
461 | 453 | ||
462 | err = add_uevent_var(envp, num_envp, &cur_index, buffer, buffer_size, | 454 | err = add_uevent_var(envp, num_envp, &cur_index, buffer, buffer_size, &cur_len, "W1_SLAVE_ID=%024LX", (u64)sl->reg_num.id); |
463 | &cur_len, "W1_SLAVE_ID=%024LX", | ||
464 | (unsigned long long)sl->reg_num.id); | ||
465 | if (err) | 455 | if (err) |
466 | return err; | 456 | return err; |
467 | 457 | ||
@@ -563,6 +553,7 @@ static int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn) | |||
563 | sl->master = dev; | 553 | sl->master = dev; |
564 | set_bit(W1_SLAVE_ACTIVE, (long *)&sl->flags); | 554 | set_bit(W1_SLAVE_ACTIVE, (long *)&sl->flags); |
565 | 555 | ||
556 | memset(&msg, 0, sizeof(msg)); | ||
566 | memcpy(&sl->reg_num, rn, sizeof(sl->reg_num)); | 557 | memcpy(&sl->reg_num, rn, sizeof(sl->reg_num)); |
567 | atomic_set(&sl->refcnt, 0); | 558 | atomic_set(&sl->refcnt, 0); |
568 | init_completion(&sl->released); | 559 | init_completion(&sl->released); |
@@ -593,7 +584,7 @@ static int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn) | |||
593 | sl->ttl = dev->slave_ttl; | 584 | sl->ttl = dev->slave_ttl; |
594 | dev->slave_count++; | 585 | dev->slave_count++; |
595 | 586 | ||
596 | memcpy(&msg.id.id, rn, sizeof(msg.id.id)); | 587 | memcpy(msg.id.id, rn, sizeof(msg.id)); |
597 | msg.type = W1_SLAVE_ADD; | 588 | msg.type = W1_SLAVE_ADD; |
598 | w1_netlink_send(dev, &msg); | 589 | w1_netlink_send(dev, &msg); |
599 | 590 | ||
@@ -611,7 +602,8 @@ static void w1_slave_detach(struct w1_slave *sl) | |||
611 | if (sl->family->fops && sl->family->fops->remove_slave) | 602 | if (sl->family->fops && sl->family->fops->remove_slave) |
612 | sl->family->fops->remove_slave(sl); | 603 | sl->family->fops->remove_slave(sl); |
613 | 604 | ||
614 | memcpy(&msg.id.id, &sl->reg_num, sizeof(msg.id.id)); | 605 | memset(&msg, 0, sizeof(msg)); |
606 | memcpy(msg.id.id, &sl->reg_num, sizeof(msg.id)); | ||
615 | msg.type = W1_SLAVE_REMOVE; | 607 | msg.type = W1_SLAVE_REMOVE; |
616 | w1_netlink_send(sl->master, &msg); | 608 | w1_netlink_send(sl->master, &msg); |
617 | 609 | ||
@@ -628,7 +620,7 @@ static struct w1_master *w1_search_master(void *data) | |||
628 | struct w1_master *dev; | 620 | struct w1_master *dev; |
629 | int found = 0; | 621 | int found = 0; |
630 | 622 | ||
631 | spin_lock_bh(&w1_mlock); | 623 | down(&w1_mlock); |
632 | list_for_each_entry(dev, &w1_masters, w1_master_entry) { | 624 | list_for_each_entry(dev, &w1_masters, w1_master_entry) { |
633 | if (dev->bus_master->data == data) { | 625 | if (dev->bus_master->data == data) { |
634 | found = 1; | 626 | found = 1; |
@@ -636,22 +628,69 @@ static struct w1_master *w1_search_master(void *data) | |||
636 | break; | 628 | break; |
637 | } | 629 | } |
638 | } | 630 | } |
639 | spin_unlock_bh(&w1_mlock); | 631 | up(&w1_mlock); |
640 | 632 | ||
641 | return (found)?dev:NULL; | 633 | return (found)?dev:NULL; |
642 | } | 634 | } |
643 | 635 | ||
636 | struct w1_master *w1_search_master_id(u32 id) | ||
637 | { | ||
638 | struct w1_master *dev; | ||
639 | int found = 0; | ||
640 | |||
641 | down(&w1_mlock); | ||
642 | list_for_each_entry(dev, &w1_masters, w1_master_entry) { | ||
643 | if (dev->id == id) { | ||
644 | found = 1; | ||
645 | atomic_inc(&dev->refcnt); | ||
646 | break; | ||
647 | } | ||
648 | } | ||
649 | up(&w1_mlock); | ||
650 | |||
651 | return (found)?dev:NULL; | ||
652 | } | ||
653 | |||
654 | struct w1_slave *w1_search_slave(struct w1_reg_num *id) | ||
655 | { | ||
656 | struct w1_master *dev; | ||
657 | struct w1_slave *sl = NULL; | ||
658 | int found = 0; | ||
659 | |||
660 | down(&w1_mlock); | ||
661 | list_for_each_entry(dev, &w1_masters, w1_master_entry) { | ||
662 | down(&dev->mutex); | ||
663 | list_for_each_entry(sl, &dev->slist, w1_slave_entry) { | ||
664 | if (sl->reg_num.family == id->family && | ||
665 | sl->reg_num.id == id->id && | ||
666 | sl->reg_num.crc == id->crc) { | ||
667 | found = 1; | ||
668 | atomic_inc(&dev->refcnt); | ||
669 | atomic_inc(&sl->refcnt); | ||
670 | break; | ||
671 | } | ||
672 | } | ||
673 | up(&dev->mutex); | ||
674 | |||
675 | if (found) | ||
676 | break; | ||
677 | } | ||
678 | up(&w1_mlock); | ||
679 | |||
680 | return (found)?sl:NULL; | ||
681 | } | ||
682 | |||
644 | void w1_reconnect_slaves(struct w1_family *f) | 683 | void w1_reconnect_slaves(struct w1_family *f) |
645 | { | 684 | { |
646 | struct w1_master *dev; | 685 | struct w1_master *dev; |
647 | 686 | ||
648 | spin_lock_bh(&w1_mlock); | 687 | down(&w1_mlock); |
649 | list_for_each_entry(dev, &w1_masters, w1_master_entry) { | 688 | list_for_each_entry(dev, &w1_masters, w1_master_entry) { |
650 | dev_dbg(&dev->dev, "Reconnecting slaves in %s into new family %02x.\n", | 689 | dev_dbg(&dev->dev, "Reconnecting slaves in %s into new family %02x.\n", |
651 | dev->name, f->fid); | 690 | dev->name, f->fid); |
652 | set_bit(W1_MASTER_NEED_RECONNECT, &dev->flags); | 691 | set_bit(W1_MASTER_NEED_RECONNECT, &dev->flags); |
653 | } | 692 | } |
654 | spin_unlock_bh(&w1_mlock); | 693 | up(&w1_mlock); |
655 | } | 694 | } |
656 | 695 | ||
657 | static void w1_slave_found(void *data, u64 rn) | 696 | static void w1_slave_found(void *data, u64 rn) |
@@ -713,7 +752,7 @@ static void w1_slave_found(void *data, u64 rn) | |||
713 | * @dev The master device to search | 752 | * @dev The master device to search |
714 | * @cb Function to call when a device is found | 753 | * @cb Function to call when a device is found |
715 | */ | 754 | */ |
716 | void w1_search(struct w1_master *dev, w1_slave_found_callback cb) | 755 | void w1_search(struct w1_master *dev, u8 search_type, w1_slave_found_callback cb) |
717 | { | 756 | { |
718 | u64 last_rn, rn, tmp64; | 757 | u64 last_rn, rn, tmp64; |
719 | int i, slave_count = 0; | 758 | int i, slave_count = 0; |
@@ -744,7 +783,7 @@ void w1_search(struct w1_master *dev, w1_slave_found_callback cb) | |||
744 | } | 783 | } |
745 | 784 | ||
746 | /* Start the search */ | 785 | /* Start the search */ |
747 | w1_write_8(dev, W1_SEARCH); | 786 | w1_write_8(dev, search_type); |
748 | for (i = 0; i < 64; ++i) { | 787 | for (i = 0; i < 64; ++i) { |
749 | /* Determine the direction/search bit */ | 788 | /* Determine the direction/search bit */ |
750 | if (i == desc_bit) | 789 | if (i == desc_bit) |
@@ -806,9 +845,9 @@ static int w1_control(void *data) | |||
806 | if (kthread_should_stop() || test_bit(W1_MASTER_NEED_EXIT, &dev->flags)) { | 845 | if (kthread_should_stop() || test_bit(W1_MASTER_NEED_EXIT, &dev->flags)) { |
807 | set_bit(W1_MASTER_NEED_EXIT, &dev->flags); | 846 | set_bit(W1_MASTER_NEED_EXIT, &dev->flags); |
808 | 847 | ||
809 | spin_lock(&w1_mlock); | 848 | down(&w1_mlock); |
810 | list_del(&dev->w1_master_entry); | 849 | list_del(&dev->w1_master_entry); |
811 | spin_unlock(&w1_mlock); | 850 | up(&w1_mlock); |
812 | 851 | ||
813 | down(&dev->mutex); | 852 | down(&dev->mutex); |
814 | list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry) { | 853 | list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry) { |
@@ -843,10 +882,31 @@ static int w1_control(void *data) | |||
843 | return 0; | 882 | return 0; |
844 | } | 883 | } |
845 | 884 | ||
885 | void w1_search_process(struct w1_master *dev, u8 search_type) | ||
886 | { | ||
887 | struct w1_slave *sl, *sln; | ||
888 | |||
889 | list_for_each_entry(sl, &dev->slist, w1_slave_entry) | ||
890 | clear_bit(W1_SLAVE_ACTIVE, (long *)&sl->flags); | ||
891 | |||
892 | w1_search_devices(dev, search_type, w1_slave_found); | ||
893 | |||
894 | list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry) { | ||
895 | if (!test_bit(W1_SLAVE_ACTIVE, (unsigned long *)&sl->flags) && !--sl->ttl) { | ||
896 | w1_slave_detach(sl); | ||
897 | |||
898 | dev->slave_count--; | ||
899 | } else if (test_bit(W1_SLAVE_ACTIVE, (unsigned long *)&sl->flags)) | ||
900 | sl->ttl = dev->slave_ttl; | ||
901 | } | ||
902 | |||
903 | if (dev->search_count > 0) | ||
904 | dev->search_count--; | ||
905 | } | ||
906 | |||
846 | int w1_process(void *data) | 907 | int w1_process(void *data) |
847 | { | 908 | { |
848 | struct w1_master *dev = (struct w1_master *) data; | 909 | struct w1_master *dev = (struct w1_master *) data; |
849 | struct w1_slave *sl, *sln; | ||
850 | 910 | ||
851 | while (!kthread_should_stop() && !test_bit(W1_MASTER_NEED_EXIT, &dev->flags)) { | 911 | while (!kthread_should_stop() && !test_bit(W1_MASTER_NEED_EXIT, &dev->flags)) { |
852 | try_to_freeze(); | 912 | try_to_freeze(); |
@@ -864,22 +924,7 @@ int w1_process(void *data) | |||
864 | if (down_interruptible(&dev->mutex)) | 924 | if (down_interruptible(&dev->mutex)) |
865 | continue; | 925 | continue; |
866 | 926 | ||
867 | list_for_each_entry(sl, &dev->slist, w1_slave_entry) | 927 | w1_search_process(dev, W1_SEARCH); |
868 | clear_bit(W1_SLAVE_ACTIVE, (long *)&sl->flags); | ||
869 | |||
870 | w1_search_devices(dev, w1_slave_found); | ||
871 | |||
872 | list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry) { | ||
873 | if (!test_bit(W1_SLAVE_ACTIVE, (unsigned long *)&sl->flags) && !--sl->ttl) { | ||
874 | w1_slave_detach(sl); | ||
875 | |||
876 | dev->slave_count--; | ||
877 | } else if (test_bit(W1_SLAVE_ACTIVE, (unsigned long *)&sl->flags)) | ||
878 | sl->ttl = dev->slave_ttl; | ||
879 | } | ||
880 | |||
881 | if (dev->search_count > 0) | ||
882 | dev->search_count--; | ||
883 | 928 | ||
884 | up(&dev->mutex); | 929 | up(&dev->mutex); |
885 | } | 930 | } |
@@ -895,6 +940,8 @@ static int w1_init(void) | |||
895 | 940 | ||
896 | printk(KERN_INFO "Driver for 1-wire Dallas network protocol.\n"); | 941 | printk(KERN_INFO "Driver for 1-wire Dallas network protocol.\n"); |
897 | 942 | ||
943 | w1_init_netlink(); | ||
944 | |||
898 | retval = bus_register(&w1_bus_type); | 945 | retval = bus_register(&w1_bus_type); |
899 | if (retval) { | 946 | if (retval) { |
900 | printk(KERN_ERR "Failed to register bus. err=%d.\n", retval); | 947 | printk(KERN_ERR "Failed to register bus. err=%d.\n", retval); |
@@ -947,6 +994,8 @@ static void w1_fini(void) | |||
947 | list_for_each_entry(dev, &w1_masters, w1_master_entry) | 994 | list_for_each_entry(dev, &w1_masters, w1_master_entry) |
948 | __w1_remove_master_device(dev); | 995 | __w1_remove_master_device(dev); |
949 | 996 | ||
997 | w1_fini_netlink(); | ||
998 | |||
950 | kthread_stop(w1_control_thread); | 999 | kthread_stop(w1_control_thread); |
951 | 1000 | ||
952 | driver_unregister(&w1_slave_driver); | 1001 | driver_unregister(&w1_slave_driver); |
diff --git a/drivers/w1/w1.h b/drivers/w1/w1.h index 02e8caddfb36..e8c96e6e7418 100644 --- a/drivers/w1/w1.h +++ b/drivers/w1/w1.h | |||
@@ -42,8 +42,6 @@ struct w1_reg_num | |||
42 | #include <linux/completion.h> | 42 | #include <linux/completion.h> |
43 | #include <linux/device.h> | 43 | #include <linux/device.h> |
44 | 44 | ||
45 | #include <net/sock.h> | ||
46 | |||
47 | #include <asm/semaphore.h> | 45 | #include <asm/semaphore.h> |
48 | 46 | ||
49 | #include "w1_family.h" | 47 | #include "w1_family.h" |
@@ -52,7 +50,7 @@ struct w1_reg_num | |||
52 | #define W1_SLAVE_DATA_SIZE 128 | 50 | #define W1_SLAVE_DATA_SIZE 128 |
53 | 51 | ||
54 | #define W1_SEARCH 0xF0 | 52 | #define W1_SEARCH 0xF0 |
55 | #define W1_CONDITIONAL_SEARCH 0xEC | 53 | #define W1_ALARM_SEARCH 0xEC |
56 | #define W1_CONVERT_TEMP 0x44 | 54 | #define W1_CONVERT_TEMP 0x44 |
57 | #define W1_SKIP_ROM 0xCC | 55 | #define W1_SKIP_ROM 0xCC |
58 | #define W1_READ_SCRATCHPAD 0xBE | 56 | #define W1_READ_SCRATCHPAD 0xBE |
@@ -145,8 +143,8 @@ struct w1_bus_master | |||
145 | */ | 143 | */ |
146 | u8 (*reset_bus)(void *); | 144 | u8 (*reset_bus)(void *); |
147 | 145 | ||
148 | /** Really nice hardware can handles the ROM searches */ | 146 | /** Really nice hardware can handles the different types of ROM search */ |
149 | void (*search)(void *, w1_slave_found_callback); | 147 | void (*search)(void *, u8, w1_slave_found_callback); |
150 | }; | 148 | }; |
151 | 149 | ||
152 | #define W1_MASTER_NEED_EXIT 0 | 150 | #define W1_MASTER_NEED_EXIT 0 |
@@ -180,12 +178,26 @@ struct w1_master | |||
180 | 178 | ||
181 | struct w1_bus_master *bus_master; | 179 | struct w1_bus_master *bus_master; |
182 | 180 | ||
183 | u32 seq, groups; | 181 | u32 seq; |
184 | struct sock *nls; | ||
185 | }; | 182 | }; |
186 | 183 | ||
187 | int w1_create_master_attributes(struct w1_master *); | 184 | int w1_create_master_attributes(struct w1_master *); |
188 | void w1_search(struct w1_master *dev, w1_slave_found_callback cb); | 185 | void w1_search(struct w1_master *dev, u8 search_type, w1_slave_found_callback cb); |
186 | void w1_search_devices(struct w1_master *dev, u8 search_type, w1_slave_found_callback cb); | ||
187 | struct w1_slave *w1_search_slave(struct w1_reg_num *id); | ||
188 | void w1_search_process(struct w1_master *dev, u8 search_type); | ||
189 | struct w1_master *w1_search_master_id(u32 id); | ||
190 | |||
191 | void w1_delay(unsigned long); | ||
192 | u8 w1_touch_bit(struct w1_master *, int); | ||
193 | u8 w1_triplet(struct w1_master *dev, int bdir); | ||
194 | void w1_write_8(struct w1_master *, u8); | ||
195 | u8 w1_read_8(struct w1_master *); | ||
196 | int w1_reset_bus(struct w1_master *); | ||
197 | u8 w1_calc_crc8(u8 *, int); | ||
198 | void w1_write_block(struct w1_master *, const u8 *, int); | ||
199 | u8 w1_read_block(struct w1_master *, u8 *, int); | ||
200 | int w1_reset_select_slave(struct w1_slave *sl); | ||
189 | 201 | ||
190 | static inline struct w1_slave* dev_to_w1_slave(struct device *dev) | 202 | static inline struct w1_slave* dev_to_w1_slave(struct device *dev) |
191 | { | 203 | { |
@@ -202,16 +214,6 @@ static inline struct w1_master* dev_to_w1_master(struct device *dev) | |||
202 | return container_of(dev, struct w1_master, dev); | 214 | return container_of(dev, struct w1_master, dev); |
203 | } | 215 | } |
204 | 216 | ||
205 | extern int w1_max_slave_count; | ||
206 | extern int w1_max_slave_ttl; | ||
207 | extern spinlock_t w1_mlock; | ||
208 | extern struct list_head w1_masters; | ||
209 | extern struct device_driver w1_master_driver; | ||
210 | extern struct device w1_master_device; | ||
211 | |||
212 | int w1_process(void *data); | ||
213 | void w1_reconnect_slaves(struct w1_family *f); | ||
214 | |||
215 | #endif /* __KERNEL__ */ | 217 | #endif /* __KERNEL__ */ |
216 | 218 | ||
217 | #endif /* __W1_H */ | 219 | #endif /* __W1_H */ |
diff --git a/drivers/w1/w1_family.h b/drivers/w1/w1_family.h index 2ca0489c716a..22a9d52c94f3 100644 --- a/drivers/w1/w1_family.h +++ b/drivers/w1/w1_family.h | |||
@@ -64,5 +64,6 @@ void __w1_family_put(struct w1_family *); | |||
64 | struct w1_family * w1_family_registered(u8); | 64 | struct w1_family * w1_family_registered(u8); |
65 | void w1_unregister_family(struct w1_family *); | 65 | void w1_unregister_family(struct w1_family *); |
66 | int w1_register_family(struct w1_family *); | 66 | int w1_register_family(struct w1_family *); |
67 | void w1_reconnect_slaves(struct w1_family *f); | ||
67 | 68 | ||
68 | #endif /* __W1_FAMILY_H */ | 69 | #endif /* __W1_FAMILY_H */ |
diff --git a/drivers/w1/w1_int.c b/drivers/w1/w1_int.c index 68565aacec7b..ae78473d11f9 100644 --- a/drivers/w1/w1_int.c +++ b/drivers/w1/w1_int.c | |||
@@ -27,10 +27,19 @@ | |||
27 | #include "w1.h" | 27 | #include "w1.h" |
28 | #include "w1_log.h" | 28 | #include "w1_log.h" |
29 | #include "w1_netlink.h" | 29 | #include "w1_netlink.h" |
30 | #include "w1_int.h" | ||
31 | 30 | ||
32 | static u32 w1_ids = 1; | 31 | static u32 w1_ids = 1; |
33 | 32 | ||
33 | extern struct device_driver w1_master_driver; | ||
34 | extern struct bus_type w1_bus_type; | ||
35 | extern struct device w1_master_device; | ||
36 | extern int w1_max_slave_count; | ||
37 | extern int w1_max_slave_ttl; | ||
38 | extern struct list_head w1_masters; | ||
39 | extern struct semaphore w1_mlock; | ||
40 | |||
41 | extern int w1_process(void *); | ||
42 | |||
34 | static struct w1_master * w1_alloc_dev(u32 id, int slave_count, int slave_ttl, | 43 | static struct w1_master * w1_alloc_dev(u32 id, int slave_count, int slave_ttl, |
35 | struct device_driver *driver, | 44 | struct device_driver *driver, |
36 | struct device *device) | 45 | struct device *device) |
@@ -74,16 +83,11 @@ static struct w1_master * w1_alloc_dev(u32 id, int slave_count, int slave_ttl, | |||
74 | 83 | ||
75 | dev->driver = driver; | 84 | dev->driver = driver; |
76 | 85 | ||
77 | dev->groups = 1; | ||
78 | dev->seq = 1; | 86 | dev->seq = 1; |
79 | dev_init_netlink(dev); | ||
80 | 87 | ||
81 | err = device_register(&dev->dev); | 88 | err = device_register(&dev->dev); |
82 | if (err) { | 89 | if (err) { |
83 | printk(KERN_ERR "Failed to register master device. err=%d\n", err); | 90 | printk(KERN_ERR "Failed to register master device. err=%d\n", err); |
84 | |||
85 | dev_fini_netlink(dev); | ||
86 | |||
87 | memset(dev, 0, sizeof(struct w1_master)); | 91 | memset(dev, 0, sizeof(struct w1_master)); |
88 | kfree(dev); | 92 | kfree(dev); |
89 | dev = NULL; | 93 | dev = NULL; |
@@ -92,7 +96,7 @@ static struct w1_master * w1_alloc_dev(u32 id, int slave_count, int slave_ttl, | |||
92 | return dev; | 96 | return dev; |
93 | } | 97 | } |
94 | 98 | ||
95 | static void w1_free_dev(struct w1_master *dev) | 99 | void w1_free_dev(struct w1_master *dev) |
96 | { | 100 | { |
97 | device_unregister(&dev->dev); | 101 | device_unregister(&dev->dev); |
98 | } | 102 | } |
@@ -131,12 +135,12 @@ int w1_add_master_device(struct w1_bus_master *master) | |||
131 | 135 | ||
132 | dev->initialized = 1; | 136 | dev->initialized = 1; |
133 | 137 | ||
134 | spin_lock(&w1_mlock); | 138 | down(&w1_mlock); |
135 | list_add(&dev->w1_master_entry, &w1_masters); | 139 | list_add(&dev->w1_master_entry, &w1_masters); |
136 | spin_unlock(&w1_mlock); | 140 | up(&w1_mlock); |
137 | 141 | ||
142 | memset(&msg, 0, sizeof(msg)); | ||
138 | msg.id.mst.id = dev->id; | 143 | msg.id.mst.id = dev->id; |
139 | msg.id.mst.pid = dev->thread->pid; | ||
140 | msg.type = W1_MASTER_ADD; | 144 | msg.type = W1_MASTER_ADD; |
141 | w1_netlink_send(dev, &msg); | 145 | w1_netlink_send(dev, &msg); |
142 | 146 | ||
@@ -153,7 +157,6 @@ err_out_free_dev: | |||
153 | void __w1_remove_master_device(struct w1_master *dev) | 157 | void __w1_remove_master_device(struct w1_master *dev) |
154 | { | 158 | { |
155 | struct w1_netlink_msg msg; | 159 | struct w1_netlink_msg msg; |
156 | pid_t pid = dev->thread->pid; | ||
157 | 160 | ||
158 | set_bit(W1_MASTER_NEED_EXIT, &dev->flags); | 161 | set_bit(W1_MASTER_NEED_EXIT, &dev->flags); |
159 | kthread_stop(dev->thread); | 162 | kthread_stop(dev->thread); |
@@ -166,8 +169,8 @@ void __w1_remove_master_device(struct w1_master *dev) | |||
166 | flush_signals(current); | 169 | flush_signals(current); |
167 | } | 170 | } |
168 | 171 | ||
172 | memset(&msg, 0, sizeof(msg)); | ||
169 | msg.id.mst.id = dev->id; | 173 | msg.id.mst.id = dev->id; |
170 | msg.id.mst.pid = pid; | ||
171 | msg.type = W1_MASTER_REMOVE; | 174 | msg.type = W1_MASTER_REMOVE; |
172 | w1_netlink_send(dev, &msg); | 175 | w1_netlink_send(dev, &msg); |
173 | 176 | ||
diff --git a/drivers/w1/w1_io.c b/drivers/w1/w1_io.c index f7f7e8bec30e..a6eb9db73591 100644 --- a/drivers/w1/w1_io.c +++ b/drivers/w1/w1_io.c | |||
@@ -26,7 +26,6 @@ | |||
26 | 26 | ||
27 | #include "w1.h" | 27 | #include "w1.h" |
28 | #include "w1_log.h" | 28 | #include "w1_log.h" |
29 | #include "w1_io.h" | ||
30 | 29 | ||
31 | static int w1_delay_parm = 1; | 30 | static int w1_delay_parm = 1; |
32 | module_param_named(delay_coef, w1_delay_parm, int, 0); | 31 | module_param_named(delay_coef, w1_delay_parm, int, 0); |
@@ -268,13 +267,13 @@ u8 w1_calc_crc8(u8 * data, int len) | |||
268 | return crc; | 267 | return crc; |
269 | } | 268 | } |
270 | 269 | ||
271 | void w1_search_devices(struct w1_master *dev, w1_slave_found_callback cb) | 270 | void w1_search_devices(struct w1_master *dev, u8 search_type, w1_slave_found_callback cb) |
272 | { | 271 | { |
273 | dev->attempts++; | 272 | dev->attempts++; |
274 | if (dev->bus_master->search) | 273 | if (dev->bus_master->search) |
275 | dev->bus_master->search(dev->bus_master->data, cb); | 274 | dev->bus_master->search(dev->bus_master->data, search_type, cb); |
276 | else | 275 | else |
277 | w1_search(dev, cb); | 276 | w1_search(dev, search_type, cb); |
278 | } | 277 | } |
279 | 278 | ||
280 | /** | 279 | /** |
@@ -300,13 +299,4 @@ int w1_reset_select_slave(struct w1_slave *sl) | |||
300 | return 0; | 299 | return 0; |
301 | } | 300 | } |
302 | 301 | ||
303 | EXPORT_SYMBOL(w1_touch_bit); | 302 | EXPORT_SYMBOL_GPL(w1_calc_crc8); |
304 | EXPORT_SYMBOL(w1_write_8); | ||
305 | EXPORT_SYMBOL(w1_read_8); | ||
306 | EXPORT_SYMBOL(w1_reset_bus); | ||
307 | EXPORT_SYMBOL(w1_calc_crc8); | ||
308 | EXPORT_SYMBOL(w1_delay); | ||
309 | EXPORT_SYMBOL(w1_read_block); | ||
310 | EXPORT_SYMBOL(w1_write_block); | ||
311 | EXPORT_SYMBOL(w1_search_devices); | ||
312 | EXPORT_SYMBOL(w1_reset_select_slave); | ||
diff --git a/drivers/w1/w1_netlink.c b/drivers/w1/w1_netlink.c index 328645da7972..d48f3acdb8a2 100644 --- a/drivers/w1/w1_netlink.c +++ b/drivers/w1/w1_netlink.c | |||
@@ -21,6 +21,7 @@ | |||
21 | 21 | ||
22 | #include <linux/skbuff.h> | 22 | #include <linux/skbuff.h> |
23 | #include <linux/netlink.h> | 23 | #include <linux/netlink.h> |
24 | #include <linux/connector.h> | ||
24 | 25 | ||
25 | #include "w1.h" | 26 | #include "w1.h" |
26 | #include "w1_log.h" | 27 | #include "w1_log.h" |
@@ -29,50 +30,204 @@ | |||
29 | #ifndef NETLINK_DISABLED | 30 | #ifndef NETLINK_DISABLED |
30 | void w1_netlink_send(struct w1_master *dev, struct w1_netlink_msg *msg) | 31 | void w1_netlink_send(struct w1_master *dev, struct w1_netlink_msg *msg) |
31 | { | 32 | { |
32 | unsigned int size; | 33 | char buf[sizeof(struct cn_msg) + sizeof(struct w1_netlink_msg)]; |
33 | struct sk_buff *skb; | 34 | struct cn_msg *m = (struct cn_msg *)buf; |
34 | struct w1_netlink_msg *data; | 35 | struct w1_netlink_msg *w = (struct w1_netlink_msg *)(m+1); |
35 | struct nlmsghdr *nlh; | ||
36 | 36 | ||
37 | if (!dev->nls) | 37 | memset(buf, 0, sizeof(buf)); |
38 | return; | ||
39 | 38 | ||
40 | size = NLMSG_SPACE(sizeof(struct w1_netlink_msg)); | 39 | m->id.idx = CN_W1_IDX; |
40 | m->id.val = CN_W1_VAL; | ||
41 | 41 | ||
42 | skb = alloc_skb(size, GFP_ATOMIC); | 42 | m->seq = dev->seq++; |
43 | if (!skb) { | 43 | m->len = sizeof(struct w1_netlink_msg); |
44 | dev_err(&dev->dev, "skb_alloc() failed.\n"); | ||
45 | return; | ||
46 | } | ||
47 | 44 | ||
48 | nlh = NLMSG_PUT(skb, 0, dev->seq++, NLMSG_DONE, size - sizeof(*nlh)); | 45 | memcpy(w, msg, sizeof(struct w1_netlink_msg)); |
49 | 46 | ||
50 | data = (struct w1_netlink_msg *)NLMSG_DATA(nlh); | 47 | cn_netlink_send(m, 0, GFP_KERNEL); |
48 | } | ||
51 | 49 | ||
52 | memcpy(data, msg, sizeof(struct w1_netlink_msg)); | 50 | static int w1_process_command_master(struct w1_master *dev, struct cn_msg *msg, |
51 | struct w1_netlink_msg *hdr, struct w1_netlink_cmd *cmd) | ||
52 | { | ||
53 | dev_dbg(&dev->dev, "%s: %s: cmd=%02x, len=%u.\n", | ||
54 | __func__, dev->name, cmd->cmd, cmd->len); | ||
53 | 55 | ||
54 | NETLINK_CB(skb).dst_group = dev->groups; | 56 | if (cmd->cmd != W1_CMD_SEARCH && cmd->cmd != W1_CMD_ALARM_SEARCH) |
55 | netlink_broadcast(dev->nls, skb, 0, dev->groups, GFP_ATOMIC); | 57 | return -EINVAL; |
56 | 58 | ||
57 | nlmsg_failure: | 59 | w1_search_process(dev, (cmd->cmd == W1_CMD_ALARM_SEARCH)?W1_ALARM_SEARCH:W1_SEARCH); |
58 | return; | 60 | return 0; |
59 | } | 61 | } |
60 | 62 | ||
61 | int dev_init_netlink(struct w1_master *dev) | 63 | static int w1_send_read_reply(struct w1_slave *sl, struct cn_msg *msg, |
64 | struct w1_netlink_msg *hdr, struct w1_netlink_cmd *cmd) | ||
62 | { | 65 | { |
63 | dev->nls = netlink_kernel_create(NETLINK_W1, 1, NULL, THIS_MODULE); | 66 | void *data; |
64 | if (!dev->nls) { | 67 | struct w1_netlink_msg *h; |
65 | printk(KERN_ERR "Failed to create new netlink socket(%u) for w1 master %s.\n", | 68 | struct w1_netlink_cmd *c; |
66 | NETLINK_W1, dev->dev.bus_id); | 69 | struct cn_msg *cm; |
70 | int err; | ||
71 | |||
72 | data = kzalloc(sizeof(struct cn_msg) + | ||
73 | sizeof(struct w1_netlink_msg) + | ||
74 | sizeof(struct w1_netlink_cmd) + | ||
75 | cmd->len, GFP_KERNEL); | ||
76 | if (!data) | ||
77 | return -ENOMEM; | ||
78 | |||
79 | cm = (struct cn_msg *)(data); | ||
80 | h = (struct w1_netlink_msg *)(cm + 1); | ||
81 | c = (struct w1_netlink_cmd *)(h + 1); | ||
82 | |||
83 | memcpy(cm, msg, sizeof(struct cn_msg)); | ||
84 | memcpy(h, hdr, sizeof(struct w1_netlink_msg)); | ||
85 | memcpy(c, cmd, sizeof(struct w1_netlink_cmd)); | ||
86 | |||
87 | cm->ack = msg->seq+1; | ||
88 | cm->len = sizeof(struct w1_netlink_msg) + sizeof(struct w1_netlink_cmd) + cmd->len; | ||
89 | |||
90 | h->len = sizeof(struct w1_netlink_cmd) + cmd->len; | ||
91 | |||
92 | memcpy(c->data, cmd->data, c->len); | ||
93 | |||
94 | err = cn_netlink_send(cm, 0, GFP_KERNEL); | ||
95 | |||
96 | kfree(data); | ||
97 | |||
98 | return err; | ||
99 | } | ||
100 | |||
101 | static int w1_process_command_slave(struct w1_slave *sl, struct cn_msg *msg, | ||
102 | struct w1_netlink_msg *hdr, struct w1_netlink_cmd *cmd) | ||
103 | { | ||
104 | int err = 0; | ||
105 | |||
106 | dev_dbg(&sl->master->dev, "%s: %02x.%012llx.%02x: cmd=%02x, len=%u.\n", | ||
107 | __func__, sl->reg_num.family, (unsigned long long)sl->reg_num.id, sl->reg_num.crc, | ||
108 | cmd->cmd, cmd->len); | ||
109 | |||
110 | switch (cmd->cmd) { | ||
111 | case W1_CMD_READ: | ||
112 | w1_read_block(sl->master, cmd->data, cmd->len); | ||
113 | w1_send_read_reply(sl, msg, hdr, cmd); | ||
114 | break; | ||
115 | case W1_CMD_WRITE: | ||
116 | w1_write_block(sl->master, cmd->data, cmd->len); | ||
117 | break; | ||
118 | case W1_CMD_SEARCH: | ||
119 | case W1_CMD_ALARM_SEARCH: | ||
120 | w1_search_process(sl->master, | ||
121 | (cmd->cmd == W1_CMD_ALARM_SEARCH)?W1_ALARM_SEARCH:W1_SEARCH); | ||
122 | break; | ||
123 | default: | ||
124 | err = -1; | ||
125 | break; | ||
67 | } | 126 | } |
68 | 127 | ||
69 | return 0; | 128 | return err; |
129 | } | ||
130 | |||
131 | static void w1_cn_callback(void *data) | ||
132 | { | ||
133 | struct cn_msg *msg = data; | ||
134 | struct w1_netlink_msg *m = (struct w1_netlink_msg *)(msg + 1); | ||
135 | struct w1_netlink_cmd *cmd; | ||
136 | struct w1_slave *sl; | ||
137 | struct w1_master *dev; | ||
138 | int err = 0; | ||
139 | |||
140 | while (msg->len && !err) { | ||
141 | struct w1_reg_num id; | ||
142 | u16 mlen = m->len; | ||
143 | u8 *cmd_data = m->data; | ||
144 | |||
145 | dev = NULL; | ||
146 | sl = NULL; | ||
147 | |||
148 | memcpy(&id, m->id.id, sizeof(id)); | ||
149 | #if 0 | ||
150 | printk("%s: %02x.%012llx.%02x: type=%02x, len=%u.\n", | ||
151 | __func__, id.family, (unsigned long long)id.id, id.crc, m->type, m->len); | ||
152 | #endif | ||
153 | if (m->len + sizeof(struct w1_netlink_msg) > msg->len) { | ||
154 | err = -E2BIG; | ||
155 | break; | ||
156 | } | ||
157 | |||
158 | if (!mlen) | ||
159 | goto out_cont; | ||
160 | |||
161 | if (m->type == W1_MASTER_CMD) { | ||
162 | dev = w1_search_master_id(m->id.mst.id); | ||
163 | } else if (m->type == W1_SLAVE_CMD) { | ||
164 | sl = w1_search_slave(&id); | ||
165 | if (sl) | ||
166 | dev = sl->master; | ||
167 | } | ||
168 | |||
169 | if (!dev) { | ||
170 | err = -ENODEV; | ||
171 | goto out_cont; | ||
172 | } | ||
173 | |||
174 | down(&dev->mutex); | ||
175 | |||
176 | if (sl && w1_reset_select_slave(sl)) { | ||
177 | err = -ENODEV; | ||
178 | goto out_up; | ||
179 | } | ||
180 | |||
181 | while (mlen) { | ||
182 | cmd = (struct w1_netlink_cmd *)cmd_data; | ||
183 | |||
184 | if (cmd->len + sizeof(struct w1_netlink_cmd) > mlen) { | ||
185 | err = -E2BIG; | ||
186 | break; | ||
187 | } | ||
188 | |||
189 | if (sl) | ||
190 | w1_process_command_slave(sl, msg, m, cmd); | ||
191 | else | ||
192 | w1_process_command_master(dev, msg, m, cmd); | ||
193 | |||
194 | cmd_data += cmd->len + sizeof(struct w1_netlink_cmd); | ||
195 | mlen -= cmd->len + sizeof(struct w1_netlink_cmd); | ||
196 | } | ||
197 | out_up: | ||
198 | atomic_dec(&dev->refcnt); | ||
199 | if (sl) | ||
200 | atomic_dec(&sl->refcnt); | ||
201 | up(&dev->mutex); | ||
202 | out_cont: | ||
203 | msg->len -= sizeof(struct w1_netlink_msg) + m->len; | ||
204 | m = (struct w1_netlink_msg *)(((u8 *)m) + sizeof(struct w1_netlink_msg) + m->len); | ||
205 | |||
206 | /* | ||
207 | * Let's allow requests for nonexisting devices. | ||
208 | */ | ||
209 | if (err == -ENODEV) | ||
210 | err = 0; | ||
211 | } | ||
212 | #if 0 | ||
213 | if (err) { | ||
214 | printk("%s: malformed message. Dropping.\n", __func__); | ||
215 | } | ||
216 | #endif | ||
70 | } | 217 | } |
71 | 218 | ||
72 | void dev_fini_netlink(struct w1_master *dev) | 219 | int w1_init_netlink(void) |
73 | { | 220 | { |
74 | if (dev->nls && dev->nls->sk_socket) | 221 | struct cb_id w1_id = {.idx = CN_W1_IDX, .val = CN_W1_VAL}; |
75 | sock_release(dev->nls->sk_socket); | 222 | |
223 | return cn_add_callback(&w1_id, "w1", &w1_cn_callback); | ||
224 | } | ||
225 | |||
226 | void w1_fini_netlink(void) | ||
227 | { | ||
228 | struct cb_id w1_id = {.idx = CN_W1_IDX, .val = CN_W1_VAL}; | ||
229 | |||
230 | cn_del_callback(&w1_id); | ||
76 | } | 231 | } |
77 | #else | 232 | #else |
78 | #warning Netlink support is disabled. Please compile with NET support enabled. | 233 | #warning Netlink support is disabled. Please compile with NET support enabled. |
@@ -81,12 +236,12 @@ void w1_netlink_send(struct w1_master *dev, struct w1_netlink_msg *msg) | |||
81 | { | 236 | { |
82 | } | 237 | } |
83 | 238 | ||
84 | int dev_init_netlink(struct w1_master *dev) | 239 | int w1_init_netlink(void) |
85 | { | 240 | { |
86 | return 0; | 241 | return 0; |
87 | } | 242 | } |
88 | 243 | ||
89 | void dev_fini_netlink(struct w1_master *dev) | 244 | void w1_fini_netlink(void) |
90 | { | 245 | { |
91 | } | 246 | } |
92 | #endif | 247 | #endif |
diff --git a/drivers/w1/w1_netlink.h b/drivers/w1/w1_netlink.h index eb0c8b3152c8..5644221f9a44 100644 --- a/drivers/w1/w1_netlink.h +++ b/drivers/w1/w1_netlink.h | |||
@@ -23,37 +23,55 @@ | |||
23 | #define __W1_NETLINK_H | 23 | #define __W1_NETLINK_H |
24 | 24 | ||
25 | #include <asm/types.h> | 25 | #include <asm/types.h> |
26 | #include <linux/connector.h> | ||
26 | 27 | ||
27 | #include "w1.h" | 28 | #include "w1.h" |
28 | 29 | ||
30 | #define CN_W1_IDX 3 | ||
31 | #define CN_W1_VAL 1 | ||
32 | |||
29 | enum w1_netlink_message_types { | 33 | enum w1_netlink_message_types { |
30 | W1_SLAVE_ADD = 0, | 34 | W1_SLAVE_ADD = 0, |
31 | W1_SLAVE_REMOVE, | 35 | W1_SLAVE_REMOVE, |
32 | W1_MASTER_ADD, | 36 | W1_MASTER_ADD, |
33 | W1_MASTER_REMOVE, | 37 | W1_MASTER_REMOVE, |
38 | W1_MASTER_CMD, | ||
39 | W1_SLAVE_CMD, | ||
34 | }; | 40 | }; |
35 | 41 | ||
36 | struct w1_netlink_msg | 42 | struct w1_netlink_msg |
37 | { | 43 | { |
38 | __u8 type; | 44 | __u8 type; |
39 | __u8 reserved[3]; | 45 | __u8 reserved; |
40 | union | 46 | __u16 len; |
41 | { | 47 | union { |
42 | struct w1_reg_num id; | 48 | __u8 id[8]; |
43 | __u64 w1_id; | 49 | struct w1_mst { |
44 | struct | ||
45 | { | ||
46 | __u32 id; | 50 | __u32 id; |
47 | __u32 pid; | 51 | __u32 res; |
48 | } mst; | 52 | } mst; |
49 | } id; | 53 | } id; |
54 | __u8 data[0]; | ||
55 | }; | ||
56 | |||
57 | #define W1_CMD_READ 0x0 | ||
58 | #define W1_CMD_WRITE 0x1 | ||
59 | #define W1_CMD_SEARCH 0x2 | ||
60 | #define W1_CMD_ALARM_SEARCH 0x3 | ||
61 | |||
62 | struct w1_netlink_cmd | ||
63 | { | ||
64 | __u8 cmd; | ||
65 | __u8 res; | ||
66 | __u16 len; | ||
67 | __u8 data[0]; | ||
50 | }; | 68 | }; |
51 | 69 | ||
52 | #ifdef __KERNEL__ | 70 | #ifdef __KERNEL__ |
53 | 71 | ||
54 | void w1_netlink_send(struct w1_master *, struct w1_netlink_msg *); | 72 | void w1_netlink_send(struct w1_master *, struct w1_netlink_msg *); |
55 | int dev_init_netlink(struct w1_master *dev); | 73 | int w1_init_netlink(void); |
56 | void dev_fini_netlink(struct w1_master *dev); | 74 | void w1_fini_netlink(void); |
57 | 75 | ||
58 | #endif /* __KERNEL__ */ | 76 | #endif /* __KERNEL__ */ |
59 | #endif /* __W1_NETLINK_H */ | 77 | #endif /* __W1_NETLINK_H */ |