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 /drivers/w1 | |
| 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>
Diffstat (limited to 'drivers/w1')
| -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 |
