aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/w1/w1_netlink.c
diff options
context:
space:
mode:
authorEvgeniy Polyakov <zbr@ioremap.net>2009-01-07 21:09:03 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2009-01-08 11:31:13 -0500
commitc7e26631d27b61d66ea6fb9b113fb92f1fa20d90 (patch)
tree6f8099b1481af05c0a34d943bba71f4f2a647c3a /drivers/w1/w1_netlink.c
parente4e056aa3518197830c884b85268799b1868e8e3 (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.c142
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
98static int w1_process_command_master(struct w1_master *dev, struct cn_msg *req_msg, 98static 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
141static 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
179static int w1_process_command_slave(struct w1_slave *sl, struct cn_msg *msg, 137static 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
162static 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
210static 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
208static int w1_process_command_root(struct cn_msg *msg, struct w1_netlink_msg *mcmd) 220static 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