diff options
author | David Fries <David@Fries.net> | 2014-01-15 23:29:17 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2014-02-07 18:40:17 -0500 |
commit | 70b34d2ed807b722413894975a8c60617defb887 (patch) | |
tree | 5dd0073cdfb48471130284bf3727223e3a100530 | |
parent | 3c6955e5aa2a7ebf18a44486be6a7f047811650b (diff) |
w1: new netlink commands, add/remove/list slaves
Introduce new commands to add, remove, and list slave devices through
the netlink interface. This can be useful to skip the search on a
static network. They could previously only be added or removed
through automatic search or sysfs, and this allows a program to only
use netlink.
Only allocate memory when needed, so move kzalloc into w1_get_slaves
where it was used.
Signed-off-by: David Fries <David@Fries.net>
Acked-by: Evgeniy Polyakov <zbr@ioremap.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r-- | drivers/w1/w1.c | 6 | ||||
-rw-r--r-- | drivers/w1/w1.h | 3 | ||||
-rw-r--r-- | drivers/w1/w1_netlink.c | 125 | ||||
-rw-r--r-- | drivers/w1/w1_netlink.h | 31 |
4 files changed, 126 insertions, 39 deletions
diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c index 4c89f85edfe6..97b35cb8b6da 100644 --- a/drivers/w1/w1.c +++ b/drivers/w1/w1.c | |||
@@ -56,8 +56,6 @@ module_param_named(slave_ttl, w1_max_slave_ttl, int, 0); | |||
56 | DEFINE_MUTEX(w1_mlock); | 56 | DEFINE_MUTEX(w1_mlock); |
57 | LIST_HEAD(w1_masters); | 57 | LIST_HEAD(w1_masters); |
58 | 58 | ||
59 | static int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn); | ||
60 | |||
61 | static int w1_master_match(struct device *dev, struct device_driver *drv) | 59 | static int w1_master_match(struct device *dev, struct device_driver *drv) |
62 | { | 60 | { |
63 | return 1; | 61 | return 1; |
@@ -444,7 +442,7 @@ static int w1_atoreg_num(struct device *dev, const char *buf, size_t count, | |||
444 | /* Searches the slaves in the w1_master and returns a pointer or NULL. | 442 | /* Searches the slaves in the w1_master and returns a pointer or NULL. |
445 | * Note: must hold the mutex | 443 | * Note: must hold the mutex |
446 | */ | 444 | */ |
447 | static struct w1_slave *w1_slave_search_device(struct w1_master *dev, | 445 | struct w1_slave *w1_slave_search_device(struct w1_master *dev, |
448 | struct w1_reg_num *rn) | 446 | struct w1_reg_num *rn) |
449 | { | 447 | { |
450 | struct w1_slave *sl; | 448 | struct w1_slave *sl; |
@@ -711,7 +709,7 @@ static int __w1_attach_slave_device(struct w1_slave *sl) | |||
711 | return 0; | 709 | return 0; |
712 | } | 710 | } |
713 | 711 | ||
714 | static int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn) | 712 | int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn) |
715 | { | 713 | { |
716 | struct w1_slave *sl; | 714 | struct w1_slave *sl; |
717 | struct w1_family *f; | 715 | struct w1_family *f; |
diff --git a/drivers/w1/w1.h b/drivers/w1/w1.h index 80fbdf908919..3376bfbb10f4 100644 --- a/drivers/w1/w1.h +++ b/drivers/w1/w1.h | |||
@@ -213,6 +213,8 @@ struct w1_slave *w1_search_slave(struct w1_reg_num *id); | |||
213 | void w1_slave_found(struct w1_master *dev, u64 rn); | 213 | void w1_slave_found(struct w1_master *dev, u64 rn); |
214 | void w1_search_process_cb(struct w1_master *dev, u8 search_type, | 214 | void w1_search_process_cb(struct w1_master *dev, u8 search_type, |
215 | w1_slave_found_callback cb); | 215 | w1_slave_found_callback cb); |
216 | struct w1_slave *w1_slave_search_device(struct w1_master *dev, | ||
217 | struct w1_reg_num *rn); | ||
216 | struct w1_master *w1_search_master_id(u32 id); | 218 | struct w1_master *w1_search_master_id(u32 id); |
217 | 219 | ||
218 | /* Disconnect and reconnect devices in the given family. Used for finding | 220 | /* Disconnect and reconnect devices in the given family. Used for finding |
@@ -221,6 +223,7 @@ struct w1_master *w1_search_master_id(u32 id); | |||
221 | * has just been registered, to 0 when it has been unregistered. | 223 | * has just been registered, to 0 when it has been unregistered. |
222 | */ | 224 | */ |
223 | void w1_reconnect_slaves(struct w1_family *f, int attach); | 225 | void w1_reconnect_slaves(struct w1_family *f, int attach); |
226 | int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn); | ||
224 | void w1_slave_detach(struct w1_slave *sl); | 227 | void w1_slave_detach(struct w1_slave *sl); |
225 | 228 | ||
226 | u8 w1_triplet(struct w1_master *dev, int bdir); | 229 | u8 w1_triplet(struct w1_master *dev, int bdir); |
diff --git a/drivers/w1/w1_netlink.c b/drivers/w1/w1_netlink.c index 73705aff53cb..747174be7b50 100644 --- a/drivers/w1/w1_netlink.c +++ b/drivers/w1/w1_netlink.c | |||
@@ -56,9 +56,6 @@ static void w1_send_slave(struct w1_master *dev, u64 rn) | |||
56 | int avail; | 56 | int avail; |
57 | u64 *data; | 57 | u64 *data; |
58 | 58 | ||
59 | /* update kernel slave list */ | ||
60 | w1_slave_found(dev, rn); | ||
61 | |||
62 | avail = dev->priv_size - cmd->len; | 59 | avail = dev->priv_size - cmd->len; |
63 | 60 | ||
64 | if (avail < 8) { | 61 | if (avail < 8) { |
@@ -79,17 +76,57 @@ static void w1_send_slave(struct w1_master *dev, u64 rn) | |||
79 | msg->len += 8; | 76 | msg->len += 8; |
80 | } | 77 | } |
81 | 78 | ||
82 | static int w1_process_search_command(struct w1_master *dev, struct cn_msg *msg, | 79 | static void w1_found_send_slave(struct w1_master *dev, u64 rn) |
83 | unsigned int avail) | ||
84 | { | 80 | { |
85 | struct w1_netlink_msg *hdr = (struct w1_netlink_msg *)(msg + 1); | 81 | /* update kernel slave list */ |
86 | struct w1_netlink_cmd *cmd = (struct w1_netlink_cmd *)(hdr + 1); | 82 | w1_slave_found(dev, rn); |
87 | int search_type = (cmd->cmd == W1_CMD_ALARM_SEARCH)?W1_ALARM_SEARCH:W1_SEARCH; | 83 | |
84 | w1_send_slave(dev, rn); | ||
85 | } | ||
86 | |||
87 | /* Get the current slave list, or search (with or without alarm) */ | ||
88 | static int w1_get_slaves(struct w1_master *dev, | ||
89 | struct cn_msg *req_msg, struct w1_netlink_msg *req_hdr, | ||
90 | struct w1_netlink_cmd *req_cmd) | ||
91 | { | ||
92 | struct cn_msg *msg; | ||
93 | struct w1_netlink_msg *hdr; | ||
94 | struct w1_netlink_cmd *cmd; | ||
95 | struct w1_slave *sl; | ||
96 | |||
97 | msg = kzalloc(PAGE_SIZE, GFP_KERNEL); | ||
98 | if (!msg) | ||
99 | return -ENOMEM; | ||
100 | |||
101 | msg->id = req_msg->id; | ||
102 | msg->seq = req_msg->seq; | ||
103 | msg->ack = 0; | ||
104 | msg->len = sizeof(struct w1_netlink_msg) + | ||
105 | sizeof(struct w1_netlink_cmd); | ||
106 | |||
107 | hdr = (struct w1_netlink_msg *)(msg + 1); | ||
108 | cmd = (struct w1_netlink_cmd *)(hdr + 1); | ||
109 | |||
110 | hdr->type = W1_MASTER_CMD; | ||
111 | hdr->id = req_hdr->id; | ||
112 | hdr->len = sizeof(struct w1_netlink_cmd); | ||
113 | |||
114 | cmd->cmd = req_cmd->cmd; | ||
115 | cmd->len = 0; | ||
88 | 116 | ||
89 | dev->priv = msg; | 117 | dev->priv = msg; |
90 | dev->priv_size = avail; | 118 | dev->priv_size = PAGE_SIZE - msg->len - sizeof(struct cn_msg); |
91 | 119 | ||
92 | w1_search_process_cb(dev, search_type, w1_send_slave); | 120 | if (req_cmd->cmd == W1_CMD_LIST_SLAVES) { |
121 | __u64 rn; | ||
122 | list_for_each_entry(sl, &dev->slist, w1_slave_entry) { | ||
123 | memcpy(&rn, &sl->reg_num, sizeof(rn)); | ||
124 | w1_send_slave(dev, rn); | ||
125 | } | ||
126 | } else { | ||
127 | w1_search_process_cb(dev, cmd->cmd == W1_CMD_ALARM_SEARCH ? | ||
128 | W1_ALARM_SEARCH : W1_SEARCH, w1_found_send_slave); | ||
129 | } | ||
93 | 130 | ||
94 | msg->ack = 0; | 131 | msg->ack = 0; |
95 | cn_netlink_send(msg, 0, GFP_KERNEL); | 132 | cn_netlink_send(msg, 0, GFP_KERNEL); |
@@ -97,6 +134,8 @@ static int w1_process_search_command(struct w1_master *dev, struct cn_msg *msg, | |||
97 | dev->priv = NULL; | 134 | dev->priv = NULL; |
98 | dev->priv_size = 0; | 135 | dev->priv_size = 0; |
99 | 136 | ||
137 | kfree(msg); | ||
138 | |||
100 | return 0; | 139 | return 0; |
101 | } | 140 | } |
102 | 141 | ||
@@ -164,38 +203,52 @@ static int w1_process_command_io(struct w1_master *dev, struct cn_msg *msg, | |||
164 | return err; | 203 | return err; |
165 | } | 204 | } |
166 | 205 | ||
167 | static int w1_process_command_master(struct w1_master *dev, struct cn_msg *req_msg, | 206 | static int w1_process_command_addremove(struct w1_master *dev, |
168 | struct w1_netlink_msg *req_hdr, struct w1_netlink_cmd *req_cmd) | 207 | struct cn_msg *msg, struct w1_netlink_msg *hdr, |
208 | struct w1_netlink_cmd *cmd) | ||
169 | { | 209 | { |
170 | int err = -EINVAL; | 210 | struct w1_slave *sl; |
171 | struct cn_msg *msg; | 211 | int err = 0; |
172 | struct w1_netlink_msg *hdr; | 212 | struct w1_reg_num *id; |
173 | struct w1_netlink_cmd *cmd; | ||
174 | 213 | ||
175 | msg = kzalloc(PAGE_SIZE, GFP_KERNEL); | 214 | if (cmd->len != 8) |
176 | if (!msg) | 215 | return -EINVAL; |
177 | return -ENOMEM; | ||
178 | 216 | ||
179 | msg->id = req_msg->id; | 217 | id = (struct w1_reg_num *)cmd->data; |
180 | msg->seq = req_msg->seq; | ||
181 | msg->ack = 0; | ||
182 | msg->len = sizeof(struct w1_netlink_msg) + sizeof(struct w1_netlink_cmd); | ||
183 | 218 | ||
184 | hdr = (struct w1_netlink_msg *)(msg + 1); | 219 | sl = w1_slave_search_device(dev, id); |
185 | cmd = (struct w1_netlink_cmd *)(hdr + 1); | 220 | switch (cmd->cmd) { |
221 | case W1_CMD_SLAVE_ADD: | ||
222 | if (sl) | ||
223 | err = -EINVAL; | ||
224 | else | ||
225 | err = w1_attach_slave_device(dev, id); | ||
226 | break; | ||
227 | case W1_CMD_SLAVE_REMOVE: | ||
228 | if (sl) | ||
229 | w1_slave_detach(sl); | ||
230 | else | ||
231 | err = -EINVAL; | ||
232 | break; | ||
233 | default: | ||
234 | err = -EINVAL; | ||
235 | break; | ||
236 | } | ||
186 | 237 | ||
187 | hdr->type = W1_MASTER_CMD; | 238 | return err; |
188 | hdr->id = req_hdr->id; | 239 | } |
189 | hdr->len = sizeof(struct w1_netlink_cmd); | ||
190 | 240 | ||
191 | cmd->cmd = req_cmd->cmd; | 241 | static int w1_process_command_master(struct w1_master *dev, |
192 | cmd->len = 0; | 242 | struct cn_msg *req_msg, struct w1_netlink_msg *req_hdr, |
243 | struct w1_netlink_cmd *req_cmd) | ||
244 | { | ||
245 | int err = -EINVAL; | ||
193 | 246 | ||
194 | switch (cmd->cmd) { | 247 | switch (req_cmd->cmd) { |
195 | case W1_CMD_SEARCH: | 248 | case W1_CMD_SEARCH: |
196 | case W1_CMD_ALARM_SEARCH: | 249 | case W1_CMD_ALARM_SEARCH: |
197 | err = w1_process_search_command(dev, msg, | 250 | case W1_CMD_LIST_SLAVES: |
198 | PAGE_SIZE - msg->len - sizeof(struct cn_msg)); | 251 | err = w1_get_slaves(dev, req_msg, req_hdr, req_cmd); |
199 | break; | 252 | break; |
200 | case W1_CMD_READ: | 253 | case W1_CMD_READ: |
201 | case W1_CMD_WRITE: | 254 | case W1_CMD_WRITE: |
@@ -205,12 +258,16 @@ static int w1_process_command_master(struct w1_master *dev, struct cn_msg *req_m | |||
205 | case W1_CMD_RESET: | 258 | case W1_CMD_RESET: |
206 | err = w1_reset_bus(dev); | 259 | err = w1_reset_bus(dev); |
207 | break; | 260 | break; |
261 | case W1_CMD_SLAVE_ADD: | ||
262 | case W1_CMD_SLAVE_REMOVE: | ||
263 | err = w1_process_command_addremove(dev, req_msg, req_hdr, | ||
264 | req_cmd); | ||
265 | break; | ||
208 | default: | 266 | default: |
209 | err = -EINVAL; | 267 | err = -EINVAL; |
210 | break; | 268 | break; |
211 | } | 269 | } |
212 | 270 | ||
213 | kfree(msg); | ||
214 | return err; | 271 | return err; |
215 | } | 272 | } |
216 | 273 | ||
diff --git a/drivers/w1/w1_netlink.h b/drivers/w1/w1_netlink.h index b0922dc29658..ea9f3e453621 100644 --- a/drivers/w1/w1_netlink.h +++ b/drivers/w1/w1_netlink.h | |||
@@ -27,6 +27,17 @@ | |||
27 | 27 | ||
28 | #include "w1.h" | 28 | #include "w1.h" |
29 | 29 | ||
30 | /** enum w1_netlink_message_types - message type | ||
31 | * | ||
32 | * @W1_SLAVE_ADD: notification that a slave device was added | ||
33 | * @W1_SLAVE_REMOVE: notification that a slave device was removed | ||
34 | * @W1_MASTER_ADD: notification that a new bus master was added | ||
35 | * @W1_MASTER_REMOVE: notification that a bus masterwas removed | ||
36 | * @W1_MASTER_CMD: initiate operations on a specific master | ||
37 | * @W1_SLAVE_CMD: sends reset, selects the slave, then does a read/write/touch | ||
38 | * operation | ||
39 | * @W1_LIST_MASTERS: used to determine the bus master identifiers | ||
40 | */ | ||
30 | enum w1_netlink_message_types { | 41 | enum w1_netlink_message_types { |
31 | W1_SLAVE_ADD = 0, | 42 | W1_SLAVE_ADD = 0, |
32 | W1_SLAVE_REMOVE, | 43 | W1_SLAVE_REMOVE, |
@@ -52,6 +63,21 @@ struct w1_netlink_msg | |||
52 | __u8 data[0]; | 63 | __u8 data[0]; |
53 | }; | 64 | }; |
54 | 65 | ||
66 | /** enum w1_commands - commands available for master or slave operations | ||
67 | * @W1_CMD_READ: read len bytes | ||
68 | * @W1_CMD_WRITE: write len bytes | ||
69 | * @W1_CMD_SEARCH: initiate a standard search, returns only the slave | ||
70 | * devices found during that search | ||
71 | * @W1_CMD_ALARM_SEARCH: search for devices that are currently alarming | ||
72 | * @W1_CMD_TOUCH: Touches a series of bytes. | ||
73 | * @W1_CMD_RESET: sends a bus reset on the given master | ||
74 | * @W1_CMD_SLAVE_ADD: adds a slave to the given master, | ||
75 | * 8 byte slave id at data[0] | ||
76 | * @W1_CMD_SLAVE_REMOVE: removes a slave to the given master, | ||
77 | * 8 byte slave id at data[0] | ||
78 | * @W1_CMD_LIST_SLAVES: list of slaves registered on this master | ||
79 | * @W1_CMD_MAX: number of available commands | ||
80 | */ | ||
55 | enum w1_commands { | 81 | enum w1_commands { |
56 | W1_CMD_READ = 0, | 82 | W1_CMD_READ = 0, |
57 | W1_CMD_WRITE, | 83 | W1_CMD_WRITE, |
@@ -59,7 +85,10 @@ enum w1_commands { | |||
59 | W1_CMD_ALARM_SEARCH, | 85 | W1_CMD_ALARM_SEARCH, |
60 | W1_CMD_TOUCH, | 86 | W1_CMD_TOUCH, |
61 | W1_CMD_RESET, | 87 | W1_CMD_RESET, |
62 | W1_CMD_MAX, | 88 | W1_CMD_SLAVE_ADD, |
89 | W1_CMD_SLAVE_REMOVE, | ||
90 | W1_CMD_LIST_SLAVES, | ||
91 | W1_CMD_MAX | ||
63 | }; | 92 | }; |
64 | 93 | ||
65 | struct w1_netlink_cmd | 94 | struct w1_netlink_cmd |