diff options
author | Evgeniy Polyakov <zbr@ioremap.net> | 2009-01-07 21:09:03 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-01-08 11:31:13 -0500 |
commit | c7e26631d27b61d66ea6fb9b113fb92f1fa20d90 (patch) | |
tree | 6f8099b1481af05c0a34d943bba71f4f2a647c3a /drivers/w1/w1_netlink.c | |
parent | e4e056aa3518197830c884b85268799b1868e8e3 (diff) |
w1: allow master IO commands
This small patchset extendes existing commands with reset, master IO and
status messages. Reset is used to reset the bus for given master device,
master IO command allows to initiate IO against bus itself not selecting
slave device first, which can be used to probe the device for example.
And status messages carry command completion status back to the userspace
(namely very useful to get -ENODEV from when requested device was not
found).
Great thanks to Paul Alfille of OWFS for testing and commands suggestions.
This patch:
Allow starting of IO not against already found slave devices, but against
the bus itself, which can be used for example to probe devices.
[akpm@linux-foundation.org: reindent switch statements]
Signed-off-by: Evgeniy Polyakov <zbr@ioremap.net>
Cc: Paul Alfille <paul.alfille@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/w1/w1_netlink.c')
-rw-r--r-- | drivers/w1/w1_netlink.c | 142 |
1 files changed, 77 insertions, 65 deletions
diff --git a/drivers/w1/w1_netlink.c b/drivers/w1/w1_netlink.c index 8a7021577f32..a94336be7654 100644 --- a/drivers/w1/w1_netlink.c +++ b/drivers/w1/w1_netlink.c | |||
@@ -95,51 +95,8 @@ static int w1_process_search_command(struct w1_master *dev, struct cn_msg *msg, | |||
95 | return 0; | 95 | return 0; |
96 | } | 96 | } |
97 | 97 | ||
98 | static int w1_process_command_master(struct w1_master *dev, struct cn_msg *req_msg, | 98 | static int w1_send_read_reply(struct cn_msg *msg, struct w1_netlink_msg *hdr, |
99 | struct w1_netlink_msg *req_hdr, struct w1_netlink_cmd *req_cmd) | 99 | struct w1_netlink_cmd *cmd) |
100 | { | ||
101 | int err = -EINVAL; | ||
102 | struct cn_msg *msg; | ||
103 | struct w1_netlink_msg *hdr; | ||
104 | struct w1_netlink_cmd *cmd; | ||
105 | |||
106 | msg = kzalloc(PAGE_SIZE, GFP_KERNEL); | ||
107 | if (!msg) | ||
108 | return -ENOMEM; | ||
109 | |||
110 | msg->id = req_msg->id; | ||
111 | msg->seq = req_msg->seq; | ||
112 | msg->ack = 0; | ||
113 | msg->len = sizeof(struct w1_netlink_msg) + sizeof(struct w1_netlink_cmd); | ||
114 | |||
115 | hdr = (struct w1_netlink_msg *)(msg + 1); | ||
116 | cmd = (struct w1_netlink_cmd *)(hdr + 1); | ||
117 | |||
118 | hdr->type = W1_MASTER_CMD; | ||
119 | hdr->id = req_hdr->id; | ||
120 | hdr->len = sizeof(struct w1_netlink_cmd); | ||
121 | |||
122 | cmd->cmd = req_cmd->cmd; | ||
123 | cmd->len = 0; | ||
124 | |||
125 | switch (cmd->cmd) { | ||
126 | case W1_CMD_SEARCH: | ||
127 | case W1_CMD_ALARM_SEARCH: | ||
128 | err = w1_process_search_command(dev, msg, | ||
129 | PAGE_SIZE - msg->len - sizeof(struct cn_msg)); | ||
130 | break; | ||
131 | default: | ||
132 | cmd->res = EINVAL; | ||
133 | cn_netlink_send(msg, 0, GFP_KERNEL); | ||
134 | break; | ||
135 | } | ||
136 | |||
137 | kfree(msg); | ||
138 | return err; | ||
139 | } | ||
140 | |||
141 | static int w1_send_read_reply(struct w1_slave *sl, struct cn_msg *msg, | ||
142 | struct w1_netlink_msg *hdr, struct w1_netlink_cmd *cmd) | ||
143 | { | 100 | { |
144 | void *data; | 101 | void *data; |
145 | struct w1_netlink_msg *h; | 102 | struct w1_netlink_msg *h; |
@@ -163,7 +120,8 @@ static int w1_send_read_reply(struct w1_slave *sl, struct cn_msg *msg, | |||
163 | memcpy(c, cmd, sizeof(struct w1_netlink_cmd)); | 120 | memcpy(c, cmd, sizeof(struct w1_netlink_cmd)); |
164 | 121 | ||
165 | cm->ack = msg->seq+1; | 122 | cm->ack = msg->seq+1; |
166 | cm->len = sizeof(struct w1_netlink_msg) + sizeof(struct w1_netlink_cmd) + cmd->len; | 123 | cm->len = sizeof(struct w1_netlink_msg) + |
124 | sizeof(struct w1_netlink_cmd) + cmd->len; | ||
167 | 125 | ||
168 | h->len = sizeof(struct w1_netlink_cmd) + cmd->len; | 126 | h->len = sizeof(struct w1_netlink_cmd) + cmd->len; |
169 | 127 | ||
@@ -176,35 +134,89 @@ static int w1_send_read_reply(struct w1_slave *sl, struct cn_msg *msg, | |||
176 | return err; | 134 | return err; |
177 | } | 135 | } |
178 | 136 | ||
179 | static int w1_process_command_slave(struct w1_slave *sl, struct cn_msg *msg, | 137 | static int w1_process_command_io(struct w1_master *dev, struct cn_msg *msg, |
180 | struct w1_netlink_msg *hdr, struct w1_netlink_cmd *cmd) | 138 | struct w1_netlink_msg *hdr, struct w1_netlink_cmd *cmd) |
181 | { | 139 | { |
182 | int err = 0; | 140 | int err = 0; |
183 | 141 | ||
184 | dev_dbg(&sl->master->dev, "%s: %02x.%012llx.%02x: cmd=%02x, len=%u.\n", | 142 | switch (cmd->cmd) { |
185 | __func__, sl->reg_num.family, (unsigned long long)sl->reg_num.id, sl->reg_num.crc, | 143 | case W1_CMD_TOUCH: |
186 | cmd->cmd, cmd->len); | 144 | w1_touch_block(dev, cmd->data, cmd->len); |
145 | w1_send_read_reply(msg, hdr, cmd); | ||
146 | break; | ||
147 | case W1_CMD_READ: | ||
148 | w1_read_block(dev, cmd->data, cmd->len); | ||
149 | w1_send_read_reply(msg, hdr, cmd); | ||
150 | break; | ||
151 | case W1_CMD_WRITE: | ||
152 | w1_write_block(dev, cmd->data, cmd->len); | ||
153 | break; | ||
154 | default: | ||
155 | err = -1; | ||
156 | break; | ||
157 | } | ||
158 | |||
159 | return err; | ||
160 | } | ||
161 | |||
162 | static int w1_process_command_master(struct w1_master *dev, struct cn_msg *req_msg, | ||
163 | struct w1_netlink_msg *req_hdr, struct w1_netlink_cmd *req_cmd) | ||
164 | { | ||
165 | int err = -EINVAL; | ||
166 | struct cn_msg *msg; | ||
167 | struct w1_netlink_msg *hdr; | ||
168 | struct w1_netlink_cmd *cmd; | ||
169 | |||
170 | msg = kzalloc(PAGE_SIZE, GFP_KERNEL); | ||
171 | if (!msg) | ||
172 | return -ENOMEM; | ||
173 | |||
174 | msg->id = req_msg->id; | ||
175 | msg->seq = req_msg->seq; | ||
176 | msg->ack = 0; | ||
177 | msg->len = sizeof(struct w1_netlink_msg) + sizeof(struct w1_netlink_cmd); | ||
178 | |||
179 | hdr = (struct w1_netlink_msg *)(msg + 1); | ||
180 | cmd = (struct w1_netlink_cmd *)(hdr + 1); | ||
181 | |||
182 | hdr->type = W1_MASTER_CMD; | ||
183 | hdr->id = req_hdr->id; | ||
184 | hdr->len = sizeof(struct w1_netlink_cmd); | ||
185 | |||
186 | cmd->cmd = req_cmd->cmd; | ||
187 | cmd->len = 0; | ||
187 | 188 | ||
188 | switch (cmd->cmd) { | 189 | switch (cmd->cmd) { |
189 | case W1_CMD_TOUCH: | 190 | case W1_CMD_SEARCH: |
190 | w1_touch_block(sl->master, cmd->data, cmd->len); | 191 | case W1_CMD_ALARM_SEARCH: |
191 | w1_send_read_reply(sl, msg, hdr, cmd); | 192 | err = w1_process_search_command(dev, msg, |
192 | break; | 193 | PAGE_SIZE - msg->len - sizeof(struct cn_msg)); |
193 | case W1_CMD_READ: | 194 | break; |
194 | w1_read_block(sl->master, cmd->data, cmd->len); | 195 | case W1_CMD_READ: |
195 | w1_send_read_reply(sl, msg, hdr, cmd); | 196 | case W1_CMD_WRITE: |
196 | break; | 197 | case W1_CMD_TOUCH: |
197 | case W1_CMD_WRITE: | 198 | err = w1_process_command_io(dev, msg, hdr, cmd); |
198 | w1_write_block(sl->master, cmd->data, cmd->len); | 199 | break; |
199 | break; | 200 | default: |
200 | default: | 201 | cmd->res = EINVAL; |
201 | err = -1; | 202 | cn_netlink_send(msg, 0, GFP_KERNEL); |
202 | break; | 203 | break; |
203 | } | 204 | } |
204 | 205 | ||
206 | kfree(msg); | ||
205 | return err; | 207 | return err; |
206 | } | 208 | } |
207 | 209 | ||
210 | static int w1_process_command_slave(struct w1_slave *sl, struct cn_msg *msg, | ||
211 | struct w1_netlink_msg *hdr, struct w1_netlink_cmd *cmd) | ||
212 | { | ||
213 | dev_dbg(&sl->master->dev, "%s: %02x.%012llx.%02x: cmd=%02x, len=%u.\n", | ||
214 | __func__, sl->reg_num.family, (unsigned long long)sl->reg_num.id, | ||
215 | sl->reg_num.crc, cmd->cmd, cmd->len); | ||
216 | |||
217 | return w1_process_command_io(sl->master, msg, hdr, cmd); | ||
218 | } | ||
219 | |||
208 | static int w1_process_command_root(struct cn_msg *msg, struct w1_netlink_msg *mcmd) | 220 | static int w1_process_command_root(struct cn_msg *msg, struct w1_netlink_msg *mcmd) |
209 | { | 221 | { |
210 | struct w1_master *m; | 222 | struct w1_master *m; |
@@ -214,7 +226,7 @@ static int w1_process_command_root(struct cn_msg *msg, struct w1_netlink_msg *mc | |||
214 | 226 | ||
215 | if (mcmd->type != W1_LIST_MASTERS) { | 227 | if (mcmd->type != W1_LIST_MASTERS) { |
216 | printk(KERN_NOTICE "%s: msg: %x.%x, wrong type: %u, len: %u.\n", | 228 | printk(KERN_NOTICE "%s: msg: %x.%x, wrong type: %u, len: %u.\n", |
217 | __func__, msg->id.idx, msg->id.val, mcmd->type, mcmd->len); | 229 | __func__, msg->id.idx, msg->id.val, mcmd->type, mcmd->len); |
218 | return -EPROTO; | 230 | return -EPROTO; |
219 | } | 231 | } |
220 | 232 | ||