aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/w1
diff options
context:
space:
mode:
authorDavid Fries <David@Fries.net>2014-01-15 23:29:17 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2014-02-07 18:40:17 -0500
commit70b34d2ed807b722413894975a8c60617defb887 (patch)
tree5dd0073cdfb48471130284bf3727223e3a100530 /drivers/w1
parent3c6955e5aa2a7ebf18a44486be6a7f047811650b (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>
Diffstat (limited to 'drivers/w1')
-rw-r--r--drivers/w1/w1.c6
-rw-r--r--drivers/w1/w1.h3
-rw-r--r--drivers/w1/w1_netlink.c125
-rw-r--r--drivers/w1/w1_netlink.h31
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);
56DEFINE_MUTEX(w1_mlock); 56DEFINE_MUTEX(w1_mlock);
57LIST_HEAD(w1_masters); 57LIST_HEAD(w1_masters);
58 58
59static int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn);
60
61static int w1_master_match(struct device *dev, struct device_driver *drv) 59static 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 */
447static struct w1_slave *w1_slave_search_device(struct w1_master *dev, 445struct 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
714static int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn) 712int 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);
213void w1_slave_found(struct w1_master *dev, u64 rn); 213void w1_slave_found(struct w1_master *dev, u64 rn);
214void w1_search_process_cb(struct w1_master *dev, u8 search_type, 214void w1_search_process_cb(struct w1_master *dev, u8 search_type,
215 w1_slave_found_callback cb); 215 w1_slave_found_callback cb);
216struct w1_slave *w1_slave_search_device(struct w1_master *dev,
217 struct w1_reg_num *rn);
216struct w1_master *w1_search_master_id(u32 id); 218struct 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 */
223void w1_reconnect_slaves(struct w1_family *f, int attach); 225void w1_reconnect_slaves(struct w1_family *f, int attach);
226int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn);
224void w1_slave_detach(struct w1_slave *sl); 227void w1_slave_detach(struct w1_slave *sl);
225 228
226u8 w1_triplet(struct w1_master *dev, int bdir); 229u8 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
82static int w1_process_search_command(struct w1_master *dev, struct cn_msg *msg, 79static 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) */
88static 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
167static int w1_process_command_master(struct w1_master *dev, struct cn_msg *req_msg, 206static 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; 241static 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 */
30enum w1_netlink_message_types { 41enum 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 */
55enum w1_commands { 81enum 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
65struct w1_netlink_cmd 94struct w1_netlink_cmd