diff options
author | Evgeniy Polyakov <johnpol@2ka.mipt.ru> | 2006-03-23 11:11:58 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2006-06-22 14:22:50 -0400 |
commit | 12003375acd879e498c6c511faf27531296f9640 (patch) | |
tree | f69001169d28c6e56e1a12e04420683620e31d79 /drivers/w1/w1.c | |
parent | 81f6075ebcf3b0800321b7d81e4845d6ad9566d8 (diff) |
[PATCH] w1: Userspace communication protocol over connector.
There are three types of messages between w1 core and userspace:
1. Events. They are generated each time new master or slave device found
either due to automatic or requested search.
2. Userspace commands. Includes read/write and search/alarm search comamnds.
3. Replies to userspace commands.
From: Evgeniy Polyakov <johnpol@2ka.mipt.ru>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/w1/w1.c')
-rw-r--r-- | drivers/w1/w1.c | 137 |
1 files changed, 93 insertions, 44 deletions
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); |