|
1 /****************************************************************************** |
|
2 * |
|
3 * $Id$ |
|
4 * |
|
5 * Copyright (C) 2006-2012 Florian Pose, Ingenieurgemeinschaft IgH |
|
6 * |
|
7 * This file is part of the IgH EtherCAT Master. |
|
8 * |
|
9 * The IgH EtherCAT Master is free software; you can redistribute it and/or |
|
10 * modify it under the terms of the GNU General Public License version 2, as |
|
11 * published by the Free Software Foundation. |
|
12 * |
|
13 * The IgH EtherCAT Master is distributed in the hope that it will be useful, |
|
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General |
|
16 * Public License for more details. |
|
17 * |
|
18 * You should have received a copy of the GNU General Public License along |
|
19 * with the IgH EtherCAT Master; if not, write to the Free Software |
|
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
|
21 * |
|
22 * --- |
|
23 * |
|
24 * The license mentioned above concerns the source code only. Using the |
|
25 * EtherCAT technology and brand is only permitted in compliance with the |
|
26 * industrial property and similar rights of Beckhoff Automation GmbH. |
|
27 * |
|
28 *****************************************************************************/ |
|
29 |
|
30 /** |
|
31 \file |
|
32 EtherCAT master character device. |
|
33 */ |
|
34 |
|
35 /*****************************************************************************/ |
|
36 |
|
37 #include <linux/module.h> |
|
38 #include <linux/vmalloc.h> |
|
39 |
|
40 #include "master.h" |
|
41 #include "slave_config.h" |
|
42 #include "voe_handler.h" |
|
43 #include "ethernet.h" |
|
44 #include "ioctl.h" |
|
45 |
|
46 /** Set to 1 to enable ioctl() latency tracing. |
|
47 * |
|
48 * Requires CPU timestamp counter! |
|
49 */ |
|
50 #define DEBUG_LATENCY 0 |
|
51 |
|
52 /** Optional compiler attributes fo ioctl() functions. |
|
53 */ |
|
54 #if 0 |
|
55 #define ATTRIBUTES __attribute__ ((__noinline__)) |
|
56 #else |
|
57 #define ATTRIBUTES |
|
58 #endif |
|
59 |
|
60 /*****************************************************************************/ |
|
61 |
|
62 /** Copies a string to an ioctl structure. |
|
63 */ |
|
64 static void ec_ioctl_strcpy( |
|
65 char *target, /**< Target. */ |
|
66 const char *source /**< Source. */ |
|
67 ) |
|
68 { |
|
69 if (source) { |
|
70 strncpy(target, source, EC_IOCTL_STRING_SIZE); |
|
71 target[EC_IOCTL_STRING_SIZE - 1] = 0; |
|
72 } else { |
|
73 target[0] = 0; |
|
74 } |
|
75 } |
|
76 |
|
77 /*****************************************************************************/ |
|
78 |
|
79 /** Get module information. |
|
80 * |
|
81 * \return Zero on success, otherwise a negative error code. |
|
82 */ |
|
83 static ATTRIBUTES int ec_ioctl_module( |
|
84 void *arg /**< Userspace address to store the results. */ |
|
85 ) |
|
86 { |
|
87 ec_ioctl_module_t data; |
|
88 |
|
89 data.ioctl_version_magic = EC_IOCTL_VERSION_MAGIC; |
|
90 data.master_count = ec_master_count(); |
|
91 |
|
92 if (copy_to_user((void __user *) arg, &data, sizeof(data))) |
|
93 return -EFAULT; |
|
94 |
|
95 return 0; |
|
96 } |
|
97 |
|
98 /*****************************************************************************/ |
|
99 |
|
100 /** Get master information. |
|
101 * |
|
102 * \return Zero on success, otherwise a negative error code. |
|
103 */ |
|
104 static ATTRIBUTES int ec_ioctl_master( |
|
105 ec_master_t *master, /**< EtherCAT master. */ |
|
106 void *arg /**< Userspace address to store the results. */ |
|
107 ) |
|
108 { |
|
109 ec_ioctl_master_t io; |
|
110 unsigned int dev_idx, j; |
|
111 |
|
112 if (down_interruptible(&master->master_sem)) { |
|
113 return -EINTR; |
|
114 } |
|
115 |
|
116 io.slave_count = master->slave_count; |
|
117 io.config_count = ec_master_config_count(master); |
|
118 io.domain_count = ec_master_domain_count(master); |
|
119 #ifdef EC_EOE |
|
120 io.eoe_handler_count = ec_master_eoe_handler_count(master); |
|
121 #endif |
|
122 io.phase = (uint8_t) master->phase; |
|
123 io.active = (uint8_t) master->active; |
|
124 io.scan_busy = master->scan_busy; |
|
125 |
|
126 up(&master->master_sem); |
|
127 |
|
128 if (down_interruptible(&master->device_sem)) { |
|
129 return -EINTR; |
|
130 } |
|
131 |
|
132 for (dev_idx = EC_DEVICE_MAIN; |
|
133 dev_idx < ec_master_num_devices(master); dev_idx++) { |
|
134 ec_device_t *device = &master->devices[dev_idx]; |
|
135 |
|
136 if (device->dev) { |
|
137 memcpy(io.devices[dev_idx].address, device->dev->dev_addr, |
|
138 ETH_ALEN); |
|
139 } else { |
|
140 memcpy(io.devices[dev_idx].address, master->macs[dev_idx], |
|
141 ETH_ALEN); |
|
142 } |
|
143 io.devices[dev_idx].attached = device->dev ? 1 : 0; |
|
144 io.devices[dev_idx].link_state = device->link_state ? 1 : 0; |
|
145 io.devices[dev_idx].tx_count = device->tx_count; |
|
146 io.devices[dev_idx].rx_count = device->rx_count; |
|
147 io.devices[dev_idx].tx_bytes = device->tx_bytes; |
|
148 io.devices[dev_idx].rx_bytes = device->rx_bytes; |
|
149 io.devices[dev_idx].tx_errors = device->tx_errors; |
|
150 for (j = 0; j < EC_RATE_COUNT; j++) { |
|
151 io.devices[dev_idx].tx_frame_rates[j] = |
|
152 device->tx_frame_rates[j]; |
|
153 io.devices[dev_idx].rx_frame_rates[j] = |
|
154 device->rx_frame_rates[j]; |
|
155 io.devices[dev_idx].tx_byte_rates[j] = |
|
156 device->tx_byte_rates[j]; |
|
157 io.devices[dev_idx].rx_byte_rates[j] = |
|
158 device->rx_byte_rates[j]; |
|
159 } |
|
160 } |
|
161 io.num_devices = ec_master_num_devices(master); |
|
162 |
|
163 io.tx_count = master->device_stats.tx_count; |
|
164 io.rx_count = master->device_stats.rx_count; |
|
165 io.tx_bytes = master->device_stats.tx_bytes; |
|
166 io.rx_bytes = master->device_stats.rx_bytes; |
|
167 for (j = 0; j < EC_RATE_COUNT; j++) { |
|
168 io.tx_frame_rates[j] = |
|
169 master->device_stats.tx_frame_rates[j]; |
|
170 io.rx_frame_rates[j] = |
|
171 master->device_stats.rx_frame_rates[j]; |
|
172 io.tx_byte_rates[j] = |
|
173 master->device_stats.tx_byte_rates[j]; |
|
174 io.rx_byte_rates[j] = |
|
175 master->device_stats.rx_byte_rates[j]; |
|
176 io.loss_rates[j] = |
|
177 master->device_stats.loss_rates[j]; |
|
178 } |
|
179 |
|
180 up(&master->device_sem); |
|
181 |
|
182 io.app_time = master->app_time; |
|
183 io.ref_clock = |
|
184 master->dc_ref_clock ? master->dc_ref_clock->ring_position : 0xffff; |
|
185 |
|
186 if (copy_to_user((void __user *) arg, &io, sizeof(io))) { |
|
187 return -EFAULT; |
|
188 } |
|
189 |
|
190 return 0; |
|
191 } |
|
192 |
|
193 /*****************************************************************************/ |
|
194 |
|
195 /** Get slave information. |
|
196 * |
|
197 * \return Zero on success, otherwise a negative error code. |
|
198 */ |
|
199 static ATTRIBUTES int ec_ioctl_slave( |
|
200 ec_master_t *master, /**< EtherCAT master. */ |
|
201 void *arg /**< Userspace address to store the results. */ |
|
202 ) |
|
203 { |
|
204 ec_ioctl_slave_t data; |
|
205 const ec_slave_t *slave; |
|
206 int i; |
|
207 |
|
208 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { |
|
209 return -EFAULT; |
|
210 } |
|
211 |
|
212 if (down_interruptible(&master->master_sem)) |
|
213 return -EINTR; |
|
214 |
|
215 if (!(slave = ec_master_find_slave_const( |
|
216 master, 0, data.position))) { |
|
217 up(&master->master_sem); |
|
218 EC_MASTER_ERR(master, "Slave %u does not exist!\n", data.position); |
|
219 return -EINVAL; |
|
220 } |
|
221 |
|
222 data.device_index = slave->device_index; |
|
223 data.vendor_id = slave->sii.vendor_id; |
|
224 data.product_code = slave->sii.product_code; |
|
225 data.revision_number = slave->sii.revision_number; |
|
226 data.serial_number = slave->sii.serial_number; |
|
227 data.alias = slave->effective_alias; |
|
228 data.boot_rx_mailbox_offset = slave->sii.boot_rx_mailbox_offset; |
|
229 data.boot_rx_mailbox_size = slave->sii.boot_rx_mailbox_size; |
|
230 data.boot_tx_mailbox_offset = slave->sii.boot_tx_mailbox_offset; |
|
231 data.boot_tx_mailbox_size = slave->sii.boot_tx_mailbox_size; |
|
232 data.std_rx_mailbox_offset = slave->sii.std_rx_mailbox_offset; |
|
233 data.std_rx_mailbox_size = slave->sii.std_rx_mailbox_size; |
|
234 data.std_tx_mailbox_offset = slave->sii.std_tx_mailbox_offset; |
|
235 data.std_tx_mailbox_size = slave->sii.std_tx_mailbox_size; |
|
236 data.mailbox_protocols = slave->sii.mailbox_protocols; |
|
237 data.has_general_category = slave->sii.has_general; |
|
238 data.coe_details = slave->sii.coe_details; |
|
239 data.general_flags = slave->sii.general_flags; |
|
240 data.current_on_ebus = slave->sii.current_on_ebus; |
|
241 for (i = 0; i < EC_MAX_PORTS; i++) { |
|
242 data.ports[i].desc = slave->ports[i].desc; |
|
243 data.ports[i].link.link_up = slave->ports[i].link.link_up; |
|
244 data.ports[i].link.loop_closed = slave->ports[i].link.loop_closed; |
|
245 data.ports[i].link.signal_detected = |
|
246 slave->ports[i].link.signal_detected; |
|
247 data.ports[i].receive_time = slave->ports[i].receive_time; |
|
248 if (slave->ports[i].next_slave) { |
|
249 data.ports[i].next_slave = |
|
250 slave->ports[i].next_slave->ring_position; |
|
251 } else { |
|
252 data.ports[i].next_slave = 0xffff; |
|
253 } |
|
254 data.ports[i].delay_to_next_dc = slave->ports[i].delay_to_next_dc; |
|
255 } |
|
256 data.fmmu_bit = slave->base_fmmu_bit_operation; |
|
257 data.dc_supported = slave->base_dc_supported; |
|
258 data.dc_range = slave->base_dc_range; |
|
259 data.has_dc_system_time = slave->has_dc_system_time; |
|
260 data.transmission_delay = slave->transmission_delay; |
|
261 data.al_state = slave->current_state; |
|
262 data.error_flag = slave->error_flag; |
|
263 |
|
264 data.sync_count = slave->sii.sync_count; |
|
265 data.sdo_count = ec_slave_sdo_count(slave); |
|
266 data.sii_nwords = slave->sii_nwords; |
|
267 ec_ioctl_strcpy(data.group, slave->sii.group); |
|
268 ec_ioctl_strcpy(data.image, slave->sii.image); |
|
269 ec_ioctl_strcpy(data.order, slave->sii.order); |
|
270 ec_ioctl_strcpy(data.name, slave->sii.name); |
|
271 |
|
272 up(&master->master_sem); |
|
273 |
|
274 if (copy_to_user((void __user *) arg, &data, sizeof(data))) |
|
275 return -EFAULT; |
|
276 |
|
277 return 0; |
|
278 } |
|
279 |
|
280 /*****************************************************************************/ |
|
281 |
|
282 /** Get slave sync manager information. |
|
283 * |
|
284 * \return Zero on success, otherwise a negative error code. |
|
285 */ |
|
286 static ATTRIBUTES int ec_ioctl_slave_sync( |
|
287 ec_master_t *master, /**< EtherCAT master. */ |
|
288 void *arg /**< Userspace address to store the results. */ |
|
289 ) |
|
290 { |
|
291 ec_ioctl_slave_sync_t data; |
|
292 const ec_slave_t *slave; |
|
293 const ec_sync_t *sync; |
|
294 |
|
295 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { |
|
296 return -EFAULT; |
|
297 } |
|
298 |
|
299 if (down_interruptible(&master->master_sem)) |
|
300 return -EINTR; |
|
301 |
|
302 if (!(slave = ec_master_find_slave_const( |
|
303 master, 0, data.slave_position))) { |
|
304 up(&master->master_sem); |
|
305 EC_MASTER_ERR(master, "Slave %u does not exist!\n", |
|
306 data.slave_position); |
|
307 return -EINVAL; |
|
308 } |
|
309 |
|
310 if (data.sync_index >= slave->sii.sync_count) { |
|
311 up(&master->master_sem); |
|
312 EC_SLAVE_ERR(slave, "Sync manager %u does not exist!\n", |
|
313 data.sync_index); |
|
314 return -EINVAL; |
|
315 } |
|
316 |
|
317 sync = &slave->sii.syncs[data.sync_index]; |
|
318 |
|
319 data.physical_start_address = sync->physical_start_address; |
|
320 data.default_size = sync->default_length; |
|
321 data.control_register = sync->control_register; |
|
322 data.enable = sync->enable; |
|
323 data.pdo_count = ec_pdo_list_count(&sync->pdos); |
|
324 |
|
325 up(&master->master_sem); |
|
326 |
|
327 if (copy_to_user((void __user *) arg, &data, sizeof(data))) |
|
328 return -EFAULT; |
|
329 |
|
330 return 0; |
|
331 } |
|
332 |
|
333 /*****************************************************************************/ |
|
334 |
|
335 /** Get slave sync manager PDO information. |
|
336 * |
|
337 * \return Zero on success, otherwise a negative error code. |
|
338 */ |
|
339 static ATTRIBUTES int ec_ioctl_slave_sync_pdo( |
|
340 ec_master_t *master, /**< EtherCAT master. */ |
|
341 void *arg /**< Userspace address to store the results. */ |
|
342 ) |
|
343 { |
|
344 ec_ioctl_slave_sync_pdo_t data; |
|
345 const ec_slave_t *slave; |
|
346 const ec_sync_t *sync; |
|
347 const ec_pdo_t *pdo; |
|
348 |
|
349 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { |
|
350 return -EFAULT; |
|
351 } |
|
352 |
|
353 if (down_interruptible(&master->master_sem)) |
|
354 return -EINTR; |
|
355 |
|
356 if (!(slave = ec_master_find_slave_const( |
|
357 master, 0, data.slave_position))) { |
|
358 up(&master->master_sem); |
|
359 EC_MASTER_ERR(master, "Slave %u does not exist!\n", |
|
360 data.slave_position); |
|
361 return -EINVAL; |
|
362 } |
|
363 |
|
364 if (data.sync_index >= slave->sii.sync_count) { |
|
365 up(&master->master_sem); |
|
366 EC_SLAVE_ERR(slave, "Sync manager %u does not exist!\n", |
|
367 data.sync_index); |
|
368 return -EINVAL; |
|
369 } |
|
370 |
|
371 sync = &slave->sii.syncs[data.sync_index]; |
|
372 if (!(pdo = ec_pdo_list_find_pdo_by_pos_const( |
|
373 &sync->pdos, data.pdo_pos))) { |
|
374 up(&master->master_sem); |
|
375 EC_SLAVE_ERR(slave, "Sync manager %u does not contain a PDO with " |
|
376 "position %u!\n", data.sync_index, data.pdo_pos); |
|
377 return -EINVAL; |
|
378 } |
|
379 |
|
380 data.index = pdo->index; |
|
381 data.entry_count = ec_pdo_entry_count(pdo); |
|
382 ec_ioctl_strcpy(data.name, pdo->name); |
|
383 |
|
384 up(&master->master_sem); |
|
385 |
|
386 if (copy_to_user((void __user *) arg, &data, sizeof(data))) |
|
387 return -EFAULT; |
|
388 |
|
389 return 0; |
|
390 } |
|
391 |
|
392 /*****************************************************************************/ |
|
393 |
|
394 /** Get slave sync manager PDO entry information. |
|
395 * |
|
396 * \return Zero on success, otherwise a negative error code. |
|
397 */ |
|
398 static ATTRIBUTES int ec_ioctl_slave_sync_pdo_entry( |
|
399 ec_master_t *master, /**< EtherCAT master. */ |
|
400 void *arg /**< Userspace address to store the results. */ |
|
401 ) |
|
402 { |
|
403 ec_ioctl_slave_sync_pdo_entry_t data; |
|
404 const ec_slave_t *slave; |
|
405 const ec_sync_t *sync; |
|
406 const ec_pdo_t *pdo; |
|
407 const ec_pdo_entry_t *entry; |
|
408 |
|
409 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { |
|
410 return -EFAULT; |
|
411 } |
|
412 |
|
413 if (down_interruptible(&master->master_sem)) |
|
414 return -EINTR; |
|
415 |
|
416 if (!(slave = ec_master_find_slave_const( |
|
417 master, 0, data.slave_position))) { |
|
418 up(&master->master_sem); |
|
419 EC_MASTER_ERR(master, "Slave %u does not exist!\n", |
|
420 data.slave_position); |
|
421 return -EINVAL; |
|
422 } |
|
423 |
|
424 if (data.sync_index >= slave->sii.sync_count) { |
|
425 up(&master->master_sem); |
|
426 EC_SLAVE_ERR(slave, "Sync manager %u does not exist!\n", |
|
427 data.sync_index); |
|
428 return -EINVAL; |
|
429 } |
|
430 |
|
431 sync = &slave->sii.syncs[data.sync_index]; |
|
432 if (!(pdo = ec_pdo_list_find_pdo_by_pos_const( |
|
433 &sync->pdos, data.pdo_pos))) { |
|
434 up(&master->master_sem); |
|
435 EC_SLAVE_ERR(slave, "Sync manager %u does not contain a PDO with " |
|
436 "position %u!\n", data.sync_index, data.pdo_pos); |
|
437 return -EINVAL; |
|
438 } |
|
439 |
|
440 if (!(entry = ec_pdo_find_entry_by_pos_const( |
|
441 pdo, data.entry_pos))) { |
|
442 up(&master->master_sem); |
|
443 EC_SLAVE_ERR(slave, "PDO 0x%04X does not contain an entry with " |
|
444 "position %u!\n", data.pdo_pos, data.entry_pos); |
|
445 return -EINVAL; |
|
446 } |
|
447 |
|
448 data.index = entry->index; |
|
449 data.subindex = entry->subindex; |
|
450 data.bit_length = entry->bit_length; |
|
451 ec_ioctl_strcpy(data.name, entry->name); |
|
452 |
|
453 up(&master->master_sem); |
|
454 |
|
455 if (copy_to_user((void __user *) arg, &data, sizeof(data))) |
|
456 return -EFAULT; |
|
457 |
|
458 return 0; |
|
459 } |
|
460 |
|
461 /*****************************************************************************/ |
|
462 |
|
463 /** Get domain information. |
|
464 * |
|
465 * \return Zero on success, otherwise a negative error code. |
|
466 */ |
|
467 static ATTRIBUTES int ec_ioctl_domain( |
|
468 ec_master_t *master, /**< EtherCAT master. */ |
|
469 void *arg /**< Userspace address to store the results. */ |
|
470 ) |
|
471 { |
|
472 ec_ioctl_domain_t data; |
|
473 const ec_domain_t *domain; |
|
474 unsigned int dev_idx; |
|
475 |
|
476 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { |
|
477 return -EFAULT; |
|
478 } |
|
479 |
|
480 if (down_interruptible(&master->master_sem)) |
|
481 return -EINTR; |
|
482 |
|
483 if (!(domain = ec_master_find_domain_const(master, data.index))) { |
|
484 up(&master->master_sem); |
|
485 EC_MASTER_ERR(master, "Domain %u does not exist!\n", data.index); |
|
486 return -EINVAL; |
|
487 } |
|
488 |
|
489 data.data_size = domain->data_size; |
|
490 data.logical_base_address = domain->logical_base_address; |
|
491 for (dev_idx = EC_DEVICE_MAIN; |
|
492 dev_idx < ec_master_num_devices(domain->master); dev_idx++) { |
|
493 data.working_counter[dev_idx] = domain->working_counter[dev_idx]; |
|
494 } |
|
495 data.expected_working_counter = domain->expected_working_counter; |
|
496 data.fmmu_count = ec_domain_fmmu_count(domain); |
|
497 |
|
498 up(&master->master_sem); |
|
499 |
|
500 if (copy_to_user((void __user *) arg, &data, sizeof(data))) |
|
501 return -EFAULT; |
|
502 |
|
503 return 0; |
|
504 } |
|
505 |
|
506 /*****************************************************************************/ |
|
507 |
|
508 /** Get domain FMMU information. |
|
509 * |
|
510 * \return Zero on success, otherwise a negative error code. |
|
511 */ |
|
512 static ATTRIBUTES int ec_ioctl_domain_fmmu( |
|
513 ec_master_t *master, /**< EtherCAT master. */ |
|
514 void *arg /**< Userspace address to store the results. */ |
|
515 ) |
|
516 { |
|
517 ec_ioctl_domain_fmmu_t data; |
|
518 const ec_domain_t *domain; |
|
519 const ec_fmmu_config_t *fmmu; |
|
520 |
|
521 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { |
|
522 return -EFAULT; |
|
523 } |
|
524 |
|
525 if (down_interruptible(&master->master_sem)) |
|
526 return -EINTR; |
|
527 |
|
528 if (!(domain = ec_master_find_domain_const(master, data.domain_index))) { |
|
529 up(&master->master_sem); |
|
530 EC_MASTER_ERR(master, "Domain %u does not exist!\n", |
|
531 data.domain_index); |
|
532 return -EINVAL; |
|
533 } |
|
534 |
|
535 if (!(fmmu = ec_domain_find_fmmu(domain, data.fmmu_index))) { |
|
536 up(&master->master_sem); |
|
537 EC_MASTER_ERR(master, "Domain %u has less than %u" |
|
538 " fmmu configurations.\n", |
|
539 data.domain_index, data.fmmu_index + 1); |
|
540 return -EINVAL; |
|
541 } |
|
542 |
|
543 data.slave_config_alias = fmmu->sc->alias; |
|
544 data.slave_config_position = fmmu->sc->position; |
|
545 data.sync_index = fmmu->sync_index; |
|
546 data.dir = fmmu->dir; |
|
547 data.logical_address = fmmu->logical_start_address; |
|
548 data.data_size = fmmu->data_size; |
|
549 |
|
550 up(&master->master_sem); |
|
551 |
|
552 if (copy_to_user((void __user *) arg, &data, sizeof(data))) |
|
553 return -EFAULT; |
|
554 |
|
555 return 0; |
|
556 } |
|
557 |
|
558 /*****************************************************************************/ |
|
559 |
|
560 /** Get domain data. |
|
561 * |
|
562 * \return Zero on success, otherwise a negative error code. |
|
563 */ |
|
564 static ATTRIBUTES int ec_ioctl_domain_data( |
|
565 ec_master_t *master, /**< EtherCAT master. */ |
|
566 void *arg /**< Userspace address to store the results. */ |
|
567 ) |
|
568 { |
|
569 ec_ioctl_domain_data_t data; |
|
570 const ec_domain_t *domain; |
|
571 |
|
572 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { |
|
573 return -EFAULT; |
|
574 } |
|
575 |
|
576 if (down_interruptible(&master->master_sem)) |
|
577 return -EINTR; |
|
578 |
|
579 if (!(domain = ec_master_find_domain_const(master, data.domain_index))) { |
|
580 up(&master->master_sem); |
|
581 EC_MASTER_ERR(master, "Domain %u does not exist!\n", |
|
582 data.domain_index); |
|
583 return -EINVAL; |
|
584 } |
|
585 |
|
586 if (domain->data_size != data.data_size) { |
|
587 up(&master->master_sem); |
|
588 EC_MASTER_ERR(master, "Data size mismatch %u/%zu!\n", |
|
589 data.data_size, domain->data_size); |
|
590 return -EFAULT; |
|
591 } |
|
592 |
|
593 if (copy_to_user((void __user *) data.target, domain->data, |
|
594 domain->data_size)) { |
|
595 up(&master->master_sem); |
|
596 return -EFAULT; |
|
597 } |
|
598 |
|
599 up(&master->master_sem); |
|
600 return 0; |
|
601 } |
|
602 |
|
603 /*****************************************************************************/ |
|
604 |
|
605 /** Set master debug level. |
|
606 * |
|
607 * \return Zero on success, otherwise a negative error code. |
|
608 */ |
|
609 static ATTRIBUTES int ec_ioctl_master_debug( |
|
610 ec_master_t *master, /**< EtherCAT master. */ |
|
611 void *arg /**< ioctl() argument. */ |
|
612 ) |
|
613 { |
|
614 return ec_master_debug_level(master, (unsigned long) arg); |
|
615 } |
|
616 |
|
617 /*****************************************************************************/ |
|
618 |
|
619 /** Issue a bus scan. |
|
620 * |
|
621 * \return Always zero (success). |
|
622 */ |
|
623 static ATTRIBUTES int ec_ioctl_master_rescan( |
|
624 ec_master_t *master, /**< EtherCAT master. */ |
|
625 void *arg /**< ioctl() argument. */ |
|
626 ) |
|
627 { |
|
628 master->fsm.rescan_required = 1; |
|
629 return 0; |
|
630 } |
|
631 |
|
632 /*****************************************************************************/ |
|
633 |
|
634 /** Set slave state. |
|
635 * |
|
636 * \return Zero on success, otherwise a negative error code. |
|
637 */ |
|
638 static ATTRIBUTES int ec_ioctl_slave_state( |
|
639 ec_master_t *master, /**< EtherCAT master. */ |
|
640 void *arg /**< ioctl() argument. */ |
|
641 ) |
|
642 { |
|
643 ec_ioctl_slave_state_t data; |
|
644 ec_slave_t *slave; |
|
645 |
|
646 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { |
|
647 return -EFAULT; |
|
648 } |
|
649 |
|
650 if (down_interruptible(&master->master_sem)) |
|
651 return -EINTR; |
|
652 |
|
653 if (!(slave = ec_master_find_slave( |
|
654 master, 0, data.slave_position))) { |
|
655 up(&master->master_sem); |
|
656 EC_MASTER_ERR(master, "Slave %u does not exist!\n", |
|
657 data.slave_position); |
|
658 return -EINVAL; |
|
659 } |
|
660 |
|
661 ec_slave_request_state(slave, data.al_state); |
|
662 |
|
663 up(&master->master_sem); |
|
664 return 0; |
|
665 } |
|
666 |
|
667 /*****************************************************************************/ |
|
668 |
|
669 /** Get slave SDO information. |
|
670 * |
|
671 * \return Zero on success, otherwise a negative error code. |
|
672 */ |
|
673 static ATTRIBUTES int ec_ioctl_slave_sdo( |
|
674 ec_master_t *master, /**< EtherCAT master. */ |
|
675 void *arg /**< ioctl() argument. */ |
|
676 ) |
|
677 { |
|
678 ec_ioctl_slave_sdo_t data; |
|
679 const ec_slave_t *slave; |
|
680 const ec_sdo_t *sdo; |
|
681 |
|
682 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { |
|
683 return -EFAULT; |
|
684 } |
|
685 |
|
686 if (down_interruptible(&master->master_sem)) |
|
687 return -EINTR; |
|
688 |
|
689 if (!(slave = ec_master_find_slave_const( |
|
690 master, 0, data.slave_position))) { |
|
691 up(&master->master_sem); |
|
692 EC_MASTER_ERR(master, "Slave %u does not exist!\n", |
|
693 data.slave_position); |
|
694 return -EINVAL; |
|
695 } |
|
696 |
|
697 if (!(sdo = ec_slave_get_sdo_by_pos_const( |
|
698 slave, data.sdo_position))) { |
|
699 up(&master->master_sem); |
|
700 EC_SLAVE_ERR(slave, "SDO %u does not exist!\n", data.sdo_position); |
|
701 return -EINVAL; |
|
702 } |
|
703 |
|
704 data.sdo_index = sdo->index; |
|
705 data.max_subindex = sdo->max_subindex; |
|
706 ec_ioctl_strcpy(data.name, sdo->name); |
|
707 |
|
708 up(&master->master_sem); |
|
709 |
|
710 if (copy_to_user((void __user *) arg, &data, sizeof(data))) |
|
711 return -EFAULT; |
|
712 |
|
713 return 0; |
|
714 } |
|
715 |
|
716 /*****************************************************************************/ |
|
717 |
|
718 /** Get slave SDO entry information. |
|
719 * |
|
720 * \return Zero on success, otherwise a negative error code. |
|
721 */ |
|
722 static ATTRIBUTES int ec_ioctl_slave_sdo_entry( |
|
723 ec_master_t *master, /**< EtherCAT master. */ |
|
724 void *arg /**< ioctl() argument. */ |
|
725 ) |
|
726 { |
|
727 ec_ioctl_slave_sdo_entry_t data; |
|
728 const ec_slave_t *slave; |
|
729 const ec_sdo_t *sdo; |
|
730 const ec_sdo_entry_t *entry; |
|
731 |
|
732 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { |
|
733 return -EFAULT; |
|
734 } |
|
735 |
|
736 if (down_interruptible(&master->master_sem)) |
|
737 return -EINTR; |
|
738 |
|
739 if (!(slave = ec_master_find_slave_const( |
|
740 master, 0, data.slave_position))) { |
|
741 up(&master->master_sem); |
|
742 EC_MASTER_ERR(master, "Slave %u does not exist!\n", |
|
743 data.slave_position); |
|
744 return -EINVAL; |
|
745 } |
|
746 |
|
747 if (data.sdo_spec <= 0) { |
|
748 if (!(sdo = ec_slave_get_sdo_by_pos_const( |
|
749 slave, -data.sdo_spec))) { |
|
750 up(&master->master_sem); |
|
751 EC_SLAVE_ERR(slave, "SDO %u does not exist!\n", -data.sdo_spec); |
|
752 return -EINVAL; |
|
753 } |
|
754 } else { |
|
755 if (!(sdo = ec_slave_get_sdo_const( |
|
756 slave, data.sdo_spec))) { |
|
757 up(&master->master_sem); |
|
758 EC_SLAVE_ERR(slave, "SDO 0x%04X does not exist!\n", |
|
759 data.sdo_spec); |
|
760 return -EINVAL; |
|
761 } |
|
762 } |
|
763 |
|
764 if (!(entry = ec_sdo_get_entry_const( |
|
765 sdo, data.sdo_entry_subindex))) { |
|
766 up(&master->master_sem); |
|
767 EC_SLAVE_ERR(slave, "SDO entry 0x%04X:%02X does not exist!\n", |
|
768 sdo->index, data.sdo_entry_subindex); |
|
769 return -EINVAL; |
|
770 } |
|
771 |
|
772 data.data_type = entry->data_type; |
|
773 data.bit_length = entry->bit_length; |
|
774 data.read_access[EC_SDO_ENTRY_ACCESS_PREOP] = |
|
775 entry->read_access[EC_SDO_ENTRY_ACCESS_PREOP]; |
|
776 data.read_access[EC_SDO_ENTRY_ACCESS_SAFEOP] = |
|
777 entry->read_access[EC_SDO_ENTRY_ACCESS_SAFEOP]; |
|
778 data.read_access[EC_SDO_ENTRY_ACCESS_OP] = |
|
779 entry->read_access[EC_SDO_ENTRY_ACCESS_OP]; |
|
780 data.write_access[EC_SDO_ENTRY_ACCESS_PREOP] = |
|
781 entry->write_access[EC_SDO_ENTRY_ACCESS_PREOP]; |
|
782 data.write_access[EC_SDO_ENTRY_ACCESS_SAFEOP] = |
|
783 entry->write_access[EC_SDO_ENTRY_ACCESS_SAFEOP]; |
|
784 data.write_access[EC_SDO_ENTRY_ACCESS_OP] = |
|
785 entry->write_access[EC_SDO_ENTRY_ACCESS_OP]; |
|
786 ec_ioctl_strcpy(data.description, entry->description); |
|
787 |
|
788 up(&master->master_sem); |
|
789 |
|
790 if (copy_to_user((void __user *) arg, &data, sizeof(data))) |
|
791 return -EFAULT; |
|
792 |
|
793 return 0; |
|
794 } |
|
795 |
|
796 /*****************************************************************************/ |
|
797 |
|
798 /** Upload SDO. |
|
799 * |
|
800 * \return Zero on success, otherwise a negative error code. |
|
801 */ |
|
802 static ATTRIBUTES int ec_ioctl_slave_sdo_upload( |
|
803 ec_master_t *master, /**< EtherCAT master. */ |
|
804 void *arg /**< ioctl() argument. */ |
|
805 ) |
|
806 { |
|
807 ec_ioctl_slave_sdo_upload_t data; |
|
808 uint8_t *target; |
|
809 int ret; |
|
810 |
|
811 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { |
|
812 return -EFAULT; |
|
813 } |
|
814 |
|
815 if (!(target = kmalloc(data.target_size, GFP_KERNEL))) { |
|
816 EC_MASTER_ERR(master, "Failed to allocate %zu bytes" |
|
817 " for SDO upload.\n", data.target_size); |
|
818 return -ENOMEM; |
|
819 } |
|
820 |
|
821 ret = ecrt_master_sdo_upload(master, data.slave_position, |
|
822 data.sdo_index, data.sdo_entry_subindex, target, |
|
823 data.target_size, &data.data_size, &data.abort_code); |
|
824 |
|
825 if (!ret) { |
|
826 if (copy_to_user((void __user *) data.target, |
|
827 target, data.data_size)) { |
|
828 kfree(target); |
|
829 return -EFAULT; |
|
830 } |
|
831 } |
|
832 |
|
833 kfree(target); |
|
834 |
|
835 if (__copy_to_user((void __user *) arg, &data, sizeof(data))) { |
|
836 return -EFAULT; |
|
837 } |
|
838 |
|
839 return ret; |
|
840 } |
|
841 |
|
842 /*****************************************************************************/ |
|
843 |
|
844 /** Download SDO. |
|
845 * |
|
846 * \return Zero on success, otherwise a negative error code. |
|
847 */ |
|
848 static ATTRIBUTES int ec_ioctl_slave_sdo_download( |
|
849 ec_master_t *master, /**< EtherCAT master. */ |
|
850 void *arg /**< ioctl() argument. */ |
|
851 ) |
|
852 { |
|
853 ec_ioctl_slave_sdo_download_t data; |
|
854 uint8_t *sdo_data; |
|
855 int retval; |
|
856 |
|
857 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { |
|
858 return -EFAULT; |
|
859 } |
|
860 |
|
861 if (!(sdo_data = kmalloc(data.data_size, GFP_KERNEL))) { |
|
862 EC_MASTER_ERR(master, "Failed to allocate %zu bytes" |
|
863 " for SDO download.\n", data.data_size); |
|
864 return -ENOMEM; |
|
865 } |
|
866 |
|
867 if (copy_from_user(sdo_data, (void __user *) data.data, data.data_size)) { |
|
868 kfree(sdo_data); |
|
869 return -EFAULT; |
|
870 } |
|
871 |
|
872 if (data.complete_access) { |
|
873 retval = ecrt_master_sdo_download_complete(master, data.slave_position, |
|
874 data.sdo_index, sdo_data, data.data_size, &data.abort_code); |
|
875 } else { |
|
876 retval = ecrt_master_sdo_download(master, data.slave_position, |
|
877 data.sdo_index, data.sdo_entry_subindex, sdo_data, |
|
878 data.data_size, &data.abort_code); |
|
879 } |
|
880 |
|
881 kfree(sdo_data); |
|
882 |
|
883 if (__copy_to_user((void __user *) arg, &data, sizeof(data))) { |
|
884 retval = -EFAULT; |
|
885 } |
|
886 |
|
887 return retval; |
|
888 } |
|
889 |
|
890 /*****************************************************************************/ |
|
891 |
|
892 /** Read a slave's SII. |
|
893 * |
|
894 * \return Zero on success, otherwise a negative error code. |
|
895 */ |
|
896 static ATTRIBUTES int ec_ioctl_slave_sii_read( |
|
897 ec_master_t *master, /**< EtherCAT master. */ |
|
898 void *arg /**< ioctl() argument. */ |
|
899 ) |
|
900 { |
|
901 ec_ioctl_slave_sii_t data; |
|
902 const ec_slave_t *slave; |
|
903 int retval; |
|
904 |
|
905 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { |
|
906 return -EFAULT; |
|
907 } |
|
908 |
|
909 if (down_interruptible(&master->master_sem)) |
|
910 return -EINTR; |
|
911 |
|
912 if (!(slave = ec_master_find_slave_const( |
|
913 master, 0, data.slave_position))) { |
|
914 up(&master->master_sem); |
|
915 EC_MASTER_ERR(master, "Slave %u does not exist!\n", |
|
916 data.slave_position); |
|
917 return -EINVAL; |
|
918 } |
|
919 |
|
920 if (!data.nwords |
|
921 || data.offset + data.nwords > slave->sii_nwords) { |
|
922 up(&master->master_sem); |
|
923 EC_SLAVE_ERR(slave, "Invalid SII read offset/size %u/%u for slave SII" |
|
924 " size %zu!\n", data.offset, data.nwords, slave->sii_nwords); |
|
925 return -EINVAL; |
|
926 } |
|
927 |
|
928 if (copy_to_user((void __user *) data.words, |
|
929 slave->sii_words + data.offset, data.nwords * 2)) |
|
930 retval = -EFAULT; |
|
931 else |
|
932 retval = 0; |
|
933 |
|
934 up(&master->master_sem); |
|
935 return retval; |
|
936 } |
|
937 |
|
938 /*****************************************************************************/ |
|
939 |
|
940 /** Write a slave's SII. |
|
941 * |
|
942 * \return Zero on success, otherwise a negative error code. |
|
943 */ |
|
944 static ATTRIBUTES int ec_ioctl_slave_sii_write( |
|
945 ec_master_t *master, /**< EtherCAT master. */ |
|
946 void *arg /**< ioctl() argument. */ |
|
947 ) |
|
948 { |
|
949 ec_ioctl_slave_sii_t data; |
|
950 ec_slave_t *slave; |
|
951 unsigned int byte_size; |
|
952 uint16_t *words; |
|
953 ec_sii_write_request_t request; |
|
954 |
|
955 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { |
|
956 return -EFAULT; |
|
957 } |
|
958 |
|
959 if (!data.nwords) { |
|
960 return 0; |
|
961 } |
|
962 |
|
963 byte_size = sizeof(uint16_t) * data.nwords; |
|
964 if (!(words = kmalloc(byte_size, GFP_KERNEL))) { |
|
965 EC_MASTER_ERR(master, "Failed to allocate %u bytes" |
|
966 " for SII contents.\n", byte_size); |
|
967 return -ENOMEM; |
|
968 } |
|
969 |
|
970 if (copy_from_user(words, |
|
971 (void __user *) data.words, byte_size)) { |
|
972 kfree(words); |
|
973 return -EFAULT; |
|
974 } |
|
975 |
|
976 if (down_interruptible(&master->master_sem)) { |
|
977 kfree(words); |
|
978 return -EINTR; |
|
979 } |
|
980 |
|
981 if (!(slave = ec_master_find_slave( |
|
982 master, 0, data.slave_position))) { |
|
983 up(&master->master_sem); |
|
984 EC_MASTER_ERR(master, "Slave %u does not exist!\n", |
|
985 data.slave_position); |
|
986 kfree(words); |
|
987 return -EINVAL; |
|
988 } |
|
989 |
|
990 // init SII write request |
|
991 INIT_LIST_HEAD(&request.list); |
|
992 request.slave = slave; |
|
993 request.words = words; |
|
994 request.offset = data.offset; |
|
995 request.nwords = data.nwords; |
|
996 request.state = EC_INT_REQUEST_QUEUED; |
|
997 |
|
998 // schedule SII write request. |
|
999 list_add_tail(&request.list, &master->sii_requests); |
|
1000 |
|
1001 up(&master->master_sem); |
|
1002 |
|
1003 // wait for processing through FSM |
|
1004 if (wait_event_interruptible(master->request_queue, |
|
1005 request.state != EC_INT_REQUEST_QUEUED)) { |
|
1006 // interrupted by signal |
|
1007 down(&master->master_sem); |
|
1008 if (request.state == EC_INT_REQUEST_QUEUED) { |
|
1009 // abort request |
|
1010 list_del(&request.list); |
|
1011 up(&master->master_sem); |
|
1012 kfree(words); |
|
1013 return -EINTR; |
|
1014 } |
|
1015 up(&master->master_sem); |
|
1016 } |
|
1017 |
|
1018 // wait until master FSM has finished processing |
|
1019 wait_event(master->request_queue, request.state != EC_INT_REQUEST_BUSY); |
|
1020 |
|
1021 kfree(words); |
|
1022 |
|
1023 return request.state == EC_INT_REQUEST_SUCCESS ? 0 : -EIO; |
|
1024 } |
|
1025 |
|
1026 /*****************************************************************************/ |
|
1027 |
|
1028 /** Read a slave's registers. |
|
1029 * |
|
1030 * \return Zero on success, otherwise a negative error code. |
|
1031 */ |
|
1032 static ATTRIBUTES int ec_ioctl_slave_reg_read( |
|
1033 ec_master_t *master, /**< EtherCAT master. */ |
|
1034 void *arg /**< ioctl() argument. */ |
|
1035 ) |
|
1036 { |
|
1037 ec_ioctl_slave_reg_t io; |
|
1038 ec_slave_t *slave; |
|
1039 ec_reg_request_t request; |
|
1040 int ret; |
|
1041 |
|
1042 if (copy_from_user(&io, (void __user *) arg, sizeof(io))) { |
|
1043 return -EFAULT; |
|
1044 } |
|
1045 |
|
1046 if (!io.size) { |
|
1047 return 0; |
|
1048 } |
|
1049 |
|
1050 // init register request |
|
1051 ret = ec_reg_request_init(&request, io.size); |
|
1052 if (ret) { |
|
1053 return ret; |
|
1054 } |
|
1055 |
|
1056 ecrt_reg_request_read(&request, io.address, io.size); |
|
1057 |
|
1058 if (down_interruptible(&master->master_sem)) { |
|
1059 ec_reg_request_clear(&request); |
|
1060 return -EINTR; |
|
1061 } |
|
1062 |
|
1063 if (!(slave = ec_master_find_slave( |
|
1064 master, 0, io.slave_position))) { |
|
1065 up(&master->master_sem); |
|
1066 ec_reg_request_clear(&request); |
|
1067 EC_MASTER_ERR(master, "Slave %u does not exist!\n", |
|
1068 io.slave_position); |
|
1069 return -EINVAL; |
|
1070 } |
|
1071 |
|
1072 // schedule request. |
|
1073 list_add_tail(&request.list, &slave->reg_requests); |
|
1074 |
|
1075 up(&master->master_sem); |
|
1076 |
|
1077 // wait for processing through FSM |
|
1078 if (wait_event_interruptible(master->request_queue, |
|
1079 request.state != EC_INT_REQUEST_QUEUED)) { |
|
1080 // interrupted by signal |
|
1081 down(&master->master_sem); |
|
1082 if (request.state == EC_INT_REQUEST_QUEUED) { |
|
1083 // abort request |
|
1084 list_del(&request.list); |
|
1085 up(&master->master_sem); |
|
1086 ec_reg_request_clear(&request); |
|
1087 return -EINTR; |
|
1088 } |
|
1089 up(&master->master_sem); |
|
1090 } |
|
1091 |
|
1092 // wait until master FSM has finished processing |
|
1093 wait_event(master->request_queue, request.state != EC_INT_REQUEST_BUSY); |
|
1094 |
|
1095 if (request.state == EC_INT_REQUEST_SUCCESS) { |
|
1096 if (copy_to_user((void __user *) io.data, request.data, io.size)) { |
|
1097 return -EFAULT; |
|
1098 } |
|
1099 } |
|
1100 ec_reg_request_clear(&request); |
|
1101 |
|
1102 return request.state == EC_INT_REQUEST_SUCCESS ? 0 : -EIO; |
|
1103 } |
|
1104 |
|
1105 /*****************************************************************************/ |
|
1106 |
|
1107 /** Write a slave's registers. |
|
1108 * |
|
1109 * \return Zero on success, otherwise a negative error code. |
|
1110 */ |
|
1111 static ATTRIBUTES int ec_ioctl_slave_reg_write( |
|
1112 ec_master_t *master, /**< EtherCAT master. */ |
|
1113 void *arg /**< ioctl() argument. */ |
|
1114 ) |
|
1115 { |
|
1116 ec_ioctl_slave_reg_t io; |
|
1117 ec_slave_t *slave; |
|
1118 ec_reg_request_t request; |
|
1119 int ret; |
|
1120 |
|
1121 if (copy_from_user(&io, (void __user *) arg, sizeof(io))) { |
|
1122 return -EFAULT; |
|
1123 } |
|
1124 |
|
1125 if (!io.size) { |
|
1126 return 0; |
|
1127 } |
|
1128 |
|
1129 // init register request |
|
1130 ret = ec_reg_request_init(&request, io.size); |
|
1131 if (ret) { |
|
1132 return ret; |
|
1133 } |
|
1134 |
|
1135 if (copy_from_user(request.data, (void __user *) io.data, io.size)) { |
|
1136 ec_reg_request_clear(&request); |
|
1137 return -EFAULT; |
|
1138 } |
|
1139 |
|
1140 ecrt_reg_request_write(&request, io.address, io.size); |
|
1141 |
|
1142 if (down_interruptible(&master->master_sem)) { |
|
1143 ec_reg_request_clear(&request); |
|
1144 return -EINTR; |
|
1145 } |
|
1146 |
|
1147 if (io.emergency) { |
|
1148 request.ring_position = io.slave_position; |
|
1149 // schedule request. |
|
1150 list_add_tail(&request.list, &master->emerg_reg_requests); |
|
1151 } |
|
1152 else { |
|
1153 if (!(slave = ec_master_find_slave(master, 0, io.slave_position))) { |
|
1154 up(&master->master_sem); |
|
1155 ec_reg_request_clear(&request); |
|
1156 EC_MASTER_ERR(master, "Slave %u does not exist!\n", |
|
1157 io.slave_position); |
|
1158 return -EINVAL; |
|
1159 } |
|
1160 |
|
1161 // schedule request. |
|
1162 list_add_tail(&request.list, &slave->reg_requests); |
|
1163 } |
|
1164 |
|
1165 up(&master->master_sem); |
|
1166 |
|
1167 // wait for processing through FSM |
|
1168 if (wait_event_interruptible(master->request_queue, |
|
1169 request.state != EC_INT_REQUEST_QUEUED)) { |
|
1170 // interrupted by signal |
|
1171 down(&master->master_sem); |
|
1172 if (request.state == EC_INT_REQUEST_QUEUED) { |
|
1173 // abort request |
|
1174 list_del(&request.list); |
|
1175 up(&master->master_sem); |
|
1176 ec_reg_request_clear(&request); |
|
1177 return -EINTR; |
|
1178 } |
|
1179 up(&master->master_sem); |
|
1180 } |
|
1181 |
|
1182 // wait until master FSM has finished processing |
|
1183 wait_event(master->request_queue, request.state != EC_INT_REQUEST_BUSY); |
|
1184 |
|
1185 ec_reg_request_clear(&request); |
|
1186 |
|
1187 return request.state == EC_INT_REQUEST_SUCCESS ? 0 : -EIO; |
|
1188 } |
|
1189 |
|
1190 /*****************************************************************************/ |
|
1191 |
|
1192 /** Get slave configuration information. |
|
1193 * |
|
1194 * \return Zero on success, otherwise a negative error code. |
|
1195 */ |
|
1196 static ATTRIBUTES int ec_ioctl_config( |
|
1197 ec_master_t *master, /**< EtherCAT master. */ |
|
1198 void *arg /**< ioctl() argument. */ |
|
1199 ) |
|
1200 { |
|
1201 ec_ioctl_config_t data; |
|
1202 const ec_slave_config_t *sc; |
|
1203 uint8_t i; |
|
1204 |
|
1205 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { |
|
1206 return -EFAULT; |
|
1207 } |
|
1208 |
|
1209 if (down_interruptible(&master->master_sem)) |
|
1210 return -EINTR; |
|
1211 |
|
1212 if (!(sc = ec_master_get_config_const( |
|
1213 master, data.config_index))) { |
|
1214 up(&master->master_sem); |
|
1215 EC_MASTER_ERR(master, "Slave config %u does not exist!\n", |
|
1216 data.config_index); |
|
1217 return -EINVAL; |
|
1218 } |
|
1219 |
|
1220 data.alias = sc->alias; |
|
1221 data.position = sc->position; |
|
1222 data.vendor_id = sc->vendor_id; |
|
1223 data.product_code = sc->product_code; |
|
1224 for (i = 0; i < EC_MAX_SYNC_MANAGERS; i++) { |
|
1225 data.syncs[i].dir = sc->sync_configs[i].dir; |
|
1226 data.syncs[i].watchdog_mode = sc->sync_configs[i].watchdog_mode; |
|
1227 data.syncs[i].pdo_count = |
|
1228 ec_pdo_list_count(&sc->sync_configs[i].pdos); |
|
1229 } |
|
1230 data.watchdog_divider = sc->watchdog_divider; |
|
1231 data.watchdog_intervals = sc->watchdog_intervals; |
|
1232 data.sdo_count = ec_slave_config_sdo_count(sc); |
|
1233 data.idn_count = ec_slave_config_idn_count(sc); |
|
1234 data.slave_position = sc->slave ? sc->slave->ring_position : -1; |
|
1235 data.dc_assign_activate = sc->dc_assign_activate; |
|
1236 for (i = 0; i < EC_SYNC_SIGNAL_COUNT; i++) { |
|
1237 data.dc_sync[i] = sc->dc_sync[i]; |
|
1238 } |
|
1239 |
|
1240 up(&master->master_sem); |
|
1241 |
|
1242 if (copy_to_user((void __user *) arg, &data, sizeof(data))) |
|
1243 return -EFAULT; |
|
1244 |
|
1245 return 0; |
|
1246 } |
|
1247 |
|
1248 /*****************************************************************************/ |
|
1249 |
|
1250 /** Get slave configuration PDO information. |
|
1251 * |
|
1252 * \return Zero on success, otherwise a negative error code. |
|
1253 */ |
|
1254 static ATTRIBUTES int ec_ioctl_config_pdo( |
|
1255 ec_master_t *master, /**< EtherCAT master. */ |
|
1256 void *arg /**< ioctl() argument. */ |
|
1257 ) |
|
1258 { |
|
1259 ec_ioctl_config_pdo_t data; |
|
1260 const ec_slave_config_t *sc; |
|
1261 const ec_pdo_t *pdo; |
|
1262 |
|
1263 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { |
|
1264 return -EFAULT; |
|
1265 } |
|
1266 |
|
1267 if (data.sync_index >= EC_MAX_SYNC_MANAGERS) { |
|
1268 EC_MASTER_ERR(master, "Invalid sync manager index %u!\n", |
|
1269 data.sync_index); |
|
1270 return -EINVAL; |
|
1271 } |
|
1272 |
|
1273 if (down_interruptible(&master->master_sem)) |
|
1274 return -EINTR; |
|
1275 |
|
1276 if (!(sc = ec_master_get_config_const( |
|
1277 master, data.config_index))) { |
|
1278 up(&master->master_sem); |
|
1279 EC_MASTER_ERR(master, "Slave config %u does not exist!\n", |
|
1280 data.config_index); |
|
1281 return -EINVAL; |
|
1282 } |
|
1283 |
|
1284 if (!(pdo = ec_pdo_list_find_pdo_by_pos_const( |
|
1285 &sc->sync_configs[data.sync_index].pdos, |
|
1286 data.pdo_pos))) { |
|
1287 up(&master->master_sem); |
|
1288 EC_MASTER_ERR(master, "Invalid PDO position!\n"); |
|
1289 return -EINVAL; |
|
1290 } |
|
1291 |
|
1292 data.index = pdo->index; |
|
1293 data.entry_count = ec_pdo_entry_count(pdo); |
|
1294 ec_ioctl_strcpy(data.name, pdo->name); |
|
1295 |
|
1296 up(&master->master_sem); |
|
1297 |
|
1298 if (copy_to_user((void __user *) arg, &data, sizeof(data))) |
|
1299 return -EFAULT; |
|
1300 |
|
1301 return 0; |
|
1302 } |
|
1303 |
|
1304 /*****************************************************************************/ |
|
1305 |
|
1306 /** Get slave configuration PDO entry information. |
|
1307 * |
|
1308 * \return Zero on success, otherwise a negative error code. |
|
1309 */ |
|
1310 static ATTRIBUTES int ec_ioctl_config_pdo_entry( |
|
1311 ec_master_t *master, /**< EtherCAT master. */ |
|
1312 void *arg /**< ioctl() argument. */ |
|
1313 ) |
|
1314 { |
|
1315 ec_ioctl_config_pdo_entry_t data; |
|
1316 const ec_slave_config_t *sc; |
|
1317 const ec_pdo_t *pdo; |
|
1318 const ec_pdo_entry_t *entry; |
|
1319 |
|
1320 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { |
|
1321 return -EFAULT; |
|
1322 } |
|
1323 |
|
1324 if (data.sync_index >= EC_MAX_SYNC_MANAGERS) { |
|
1325 EC_MASTER_ERR(master, "Invalid sync manager index %u!\n", |
|
1326 data.sync_index); |
|
1327 return -EINVAL; |
|
1328 } |
|
1329 |
|
1330 if (down_interruptible(&master->master_sem)) |
|
1331 return -EINTR; |
|
1332 |
|
1333 if (!(sc = ec_master_get_config_const( |
|
1334 master, data.config_index))) { |
|
1335 up(&master->master_sem); |
|
1336 EC_MASTER_ERR(master, "Slave config %u does not exist!\n", |
|
1337 data.config_index); |
|
1338 return -EINVAL; |
|
1339 } |
|
1340 |
|
1341 if (!(pdo = ec_pdo_list_find_pdo_by_pos_const( |
|
1342 &sc->sync_configs[data.sync_index].pdos, |
|
1343 data.pdo_pos))) { |
|
1344 up(&master->master_sem); |
|
1345 EC_MASTER_ERR(master, "Invalid PDO position!\n"); |
|
1346 return -EINVAL; |
|
1347 } |
|
1348 |
|
1349 if (!(entry = ec_pdo_find_entry_by_pos_const( |
|
1350 pdo, data.entry_pos))) { |
|
1351 up(&master->master_sem); |
|
1352 EC_MASTER_ERR(master, "Entry not found!\n"); |
|
1353 return -EINVAL; |
|
1354 } |
|
1355 |
|
1356 data.index = entry->index; |
|
1357 data.subindex = entry->subindex; |
|
1358 data.bit_length = entry->bit_length; |
|
1359 ec_ioctl_strcpy(data.name, entry->name); |
|
1360 |
|
1361 up(&master->master_sem); |
|
1362 |
|
1363 if (copy_to_user((void __user *) arg, &data, sizeof(data))) |
|
1364 return -EFAULT; |
|
1365 |
|
1366 return 0; |
|
1367 } |
|
1368 |
|
1369 /*****************************************************************************/ |
|
1370 |
|
1371 /** Get slave configuration SDO information. |
|
1372 * |
|
1373 * \return Zero on success, otherwise a negative error code. |
|
1374 */ |
|
1375 static ATTRIBUTES int ec_ioctl_config_sdo( |
|
1376 ec_master_t *master, /**< EtherCAT master. */ |
|
1377 void *arg /**< ioctl() argument. */ |
|
1378 ) |
|
1379 { |
|
1380 ec_ioctl_config_sdo_t *ioctl; |
|
1381 const ec_slave_config_t *sc; |
|
1382 const ec_sdo_request_t *req; |
|
1383 |
|
1384 if (!(ioctl = kmalloc(sizeof(*ioctl), GFP_KERNEL))) { |
|
1385 return -ENOMEM; |
|
1386 } |
|
1387 |
|
1388 if (copy_from_user(ioctl, (void __user *) arg, sizeof(*ioctl))) { |
|
1389 kfree(ioctl); |
|
1390 return -EFAULT; |
|
1391 } |
|
1392 |
|
1393 if (down_interruptible(&master->master_sem)) { |
|
1394 kfree(ioctl); |
|
1395 return -EINTR; |
|
1396 } |
|
1397 |
|
1398 if (!(sc = ec_master_get_config_const( |
|
1399 master, ioctl->config_index))) { |
|
1400 up(&master->master_sem); |
|
1401 EC_MASTER_ERR(master, "Slave config %u does not exist!\n", |
|
1402 ioctl->config_index); |
|
1403 kfree(ioctl); |
|
1404 return -EINVAL; |
|
1405 } |
|
1406 |
|
1407 if (!(req = ec_slave_config_get_sdo_by_pos_const( |
|
1408 sc, ioctl->sdo_pos))) { |
|
1409 up(&master->master_sem); |
|
1410 EC_MASTER_ERR(master, "Invalid SDO position!\n"); |
|
1411 kfree(ioctl); |
|
1412 return -EINVAL; |
|
1413 } |
|
1414 |
|
1415 ioctl->index = req->index; |
|
1416 ioctl->subindex = req->subindex; |
|
1417 ioctl->size = req->data_size; |
|
1418 memcpy(ioctl->data, req->data, |
|
1419 min((u32) ioctl->size, (u32) EC_MAX_SDO_DATA_SIZE)); |
|
1420 ioctl->complete_access = req->complete_access; |
|
1421 |
|
1422 up(&master->master_sem); |
|
1423 |
|
1424 if (copy_to_user((void __user *) arg, ioctl, sizeof(*ioctl))) { |
|
1425 kfree(ioctl); |
|
1426 return -EFAULT; |
|
1427 } |
|
1428 |
|
1429 kfree(ioctl); |
|
1430 return 0; |
|
1431 } |
|
1432 |
|
1433 /*****************************************************************************/ |
|
1434 |
|
1435 /** Get slave configuration IDN information. |
|
1436 * |
|
1437 * \return Zero on success, otherwise a negative error code. |
|
1438 */ |
|
1439 static ATTRIBUTES int ec_ioctl_config_idn( |
|
1440 ec_master_t *master, /**< EtherCAT master. */ |
|
1441 void *arg /**< ioctl() argument. */ |
|
1442 ) |
|
1443 { |
|
1444 ec_ioctl_config_idn_t *ioctl; |
|
1445 const ec_slave_config_t *sc; |
|
1446 const ec_soe_request_t *req; |
|
1447 |
|
1448 if (!(ioctl = kmalloc(sizeof(*ioctl), GFP_KERNEL))) { |
|
1449 return -ENOMEM; |
|
1450 } |
|
1451 |
|
1452 if (copy_from_user(ioctl, (void __user *) arg, sizeof(*ioctl))) { |
|
1453 kfree(ioctl); |
|
1454 return -EFAULT; |
|
1455 } |
|
1456 |
|
1457 if (down_interruptible(&master->master_sem)) { |
|
1458 kfree(ioctl); |
|
1459 return -EINTR; |
|
1460 } |
|
1461 |
|
1462 if (!(sc = ec_master_get_config_const( |
|
1463 master, ioctl->config_index))) { |
|
1464 up(&master->master_sem); |
|
1465 EC_MASTER_ERR(master, "Slave config %u does not exist!\n", |
|
1466 ioctl->config_index); |
|
1467 kfree(ioctl); |
|
1468 return -EINVAL; |
|
1469 } |
|
1470 |
|
1471 if (!(req = ec_slave_config_get_idn_by_pos_const( |
|
1472 sc, ioctl->idn_pos))) { |
|
1473 up(&master->master_sem); |
|
1474 EC_MASTER_ERR(master, "Invalid IDN position!\n"); |
|
1475 kfree(ioctl); |
|
1476 return -EINVAL; |
|
1477 } |
|
1478 |
|
1479 ioctl->drive_no = req->drive_no; |
|
1480 ioctl->idn = req->idn; |
|
1481 ioctl->state = req->state; |
|
1482 ioctl->size = req->data_size; |
|
1483 memcpy(ioctl->data, req->data, |
|
1484 min((u32) ioctl->size, (u32) EC_MAX_IDN_DATA_SIZE)); |
|
1485 |
|
1486 up(&master->master_sem); |
|
1487 |
|
1488 if (copy_to_user((void __user *) arg, ioctl, sizeof(*ioctl))) { |
|
1489 kfree(ioctl); |
|
1490 return -EFAULT; |
|
1491 } |
|
1492 |
|
1493 kfree(ioctl); |
|
1494 return 0; |
|
1495 } |
|
1496 |
|
1497 /*****************************************************************************/ |
|
1498 |
|
1499 #ifdef EC_EOE |
|
1500 |
|
1501 /** Get EoE handler information. |
|
1502 * |
|
1503 * \return Zero on success, otherwise a negative error code. |
|
1504 */ |
|
1505 static ATTRIBUTES int ec_ioctl_eoe_handler( |
|
1506 ec_master_t *master, /**< EtherCAT master. */ |
|
1507 void *arg /**< ioctl() argument. */ |
|
1508 ) |
|
1509 { |
|
1510 ec_ioctl_eoe_handler_t data; |
|
1511 const ec_eoe_t *eoe; |
|
1512 |
|
1513 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { |
|
1514 return -EFAULT; |
|
1515 } |
|
1516 |
|
1517 if (down_interruptible(&master->master_sem)) |
|
1518 return -EINTR; |
|
1519 |
|
1520 if (!(eoe = ec_master_get_eoe_handler_const(master, data.eoe_index))) { |
|
1521 up(&master->master_sem); |
|
1522 EC_MASTER_ERR(master, "EoE handler %u does not exist!\n", |
|
1523 data.eoe_index); |
|
1524 return -EINVAL; |
|
1525 } |
|
1526 |
|
1527 if (eoe->slave) { |
|
1528 data.slave_position = eoe->slave->ring_position; |
|
1529 } else { |
|
1530 data.slave_position = 0xffff; |
|
1531 } |
|
1532 snprintf(data.name, EC_DATAGRAM_NAME_SIZE, eoe->dev->name); |
|
1533 data.open = eoe->opened; |
|
1534 data.rx_bytes = eoe->stats.tx_bytes; |
|
1535 data.rx_rate = eoe->tx_rate; |
|
1536 data.tx_bytes = eoe->stats.rx_bytes; |
|
1537 data.tx_rate = eoe->tx_rate; |
|
1538 data.tx_queued_frames = eoe->tx_queued_frames; |
|
1539 data.tx_queue_size = eoe->tx_queue_size; |
|
1540 |
|
1541 up(&master->master_sem); |
|
1542 |
|
1543 if (copy_to_user((void __user *) arg, &data, sizeof(data))) |
|
1544 return -EFAULT; |
|
1545 |
|
1546 return 0; |
|
1547 } |
|
1548 |
|
1549 #endif |
|
1550 |
|
1551 /*****************************************************************************/ |
|
1552 |
|
1553 /** Request the master from userspace. |
|
1554 * |
|
1555 * \return Zero on success, otherwise a negative error code. |
|
1556 */ |
|
1557 static ATTRIBUTES int ec_ioctl_request( |
|
1558 ec_master_t *master, /**< EtherCAT master. */ |
|
1559 void *arg, /**< ioctl() argument. */ |
|
1560 ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ |
|
1561 ) |
|
1562 { |
|
1563 ec_master_t *m; |
|
1564 int ret = 0; |
|
1565 |
|
1566 m = ecrt_request_master_err(master->index); |
|
1567 if (IS_ERR(m)) { |
|
1568 ret = PTR_ERR(m); |
|
1569 } else { |
|
1570 ctx->requested = 1; |
|
1571 } |
|
1572 |
|
1573 return ret; |
|
1574 } |
|
1575 |
|
1576 /*****************************************************************************/ |
|
1577 |
|
1578 /** Create a domain. |
|
1579 * |
|
1580 * \return Domain index on success, otherwise a negative error code. |
|
1581 */ |
|
1582 static ATTRIBUTES int ec_ioctl_create_domain( |
|
1583 ec_master_t *master, /**< EtherCAT master. */ |
|
1584 void *arg, /**< ioctl() argument. */ |
|
1585 ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ |
|
1586 ) |
|
1587 { |
|
1588 ec_domain_t *domain; |
|
1589 |
|
1590 if (unlikely(!ctx->requested)) |
|
1591 return -EPERM; |
|
1592 |
|
1593 domain = ecrt_master_create_domain_err(master); |
|
1594 if (IS_ERR(domain)) |
|
1595 return PTR_ERR(domain); |
|
1596 |
|
1597 return domain->index; |
|
1598 } |
|
1599 |
|
1600 /*****************************************************************************/ |
|
1601 |
|
1602 /** Create a slave configuration. |
|
1603 * |
|
1604 * \return Zero on success, otherwise a negative error code. |
|
1605 */ |
|
1606 static ATTRIBUTES int ec_ioctl_create_slave_config( |
|
1607 ec_master_t *master, /**< EtherCAT master. */ |
|
1608 void *arg, /**< ioctl() argument. */ |
|
1609 ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ |
|
1610 ) |
|
1611 { |
|
1612 ec_ioctl_config_t data; |
|
1613 ec_slave_config_t *sc, *entry; |
|
1614 |
|
1615 if (unlikely(!ctx->requested)) |
|
1616 return -EPERM; |
|
1617 |
|
1618 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { |
|
1619 return -EFAULT; |
|
1620 } |
|
1621 |
|
1622 sc = ecrt_master_slave_config_err(master, data.alias, data.position, |
|
1623 data.vendor_id, data.product_code); |
|
1624 if (IS_ERR(sc)) |
|
1625 return PTR_ERR(sc); |
|
1626 |
|
1627 data.config_index = 0; |
|
1628 |
|
1629 if (down_interruptible(&master->master_sem)) |
|
1630 return -EINTR; |
|
1631 |
|
1632 list_for_each_entry(entry, &master->configs, list) { |
|
1633 if (entry == sc) |
|
1634 break; |
|
1635 data.config_index++; |
|
1636 } |
|
1637 |
|
1638 up(&master->master_sem); |
|
1639 |
|
1640 if (copy_to_user((void __user *) arg, &data, sizeof(data))) |
|
1641 return -EFAULT; |
|
1642 |
|
1643 return 0; |
|
1644 } |
|
1645 |
|
1646 /*****************************************************************************/ |
|
1647 |
|
1648 /** Select the DC reference clock. |
|
1649 * |
|
1650 * \return Zero on success, otherwise a negative error code. |
|
1651 */ |
|
1652 static ATTRIBUTES int ec_ioctl_select_ref_clock( |
|
1653 ec_master_t *master, /**< EtherCAT master. */ |
|
1654 void *arg, /**< ioctl() argument. */ |
|
1655 ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ |
|
1656 ) |
|
1657 { |
|
1658 unsigned long config_index = (unsigned long) arg; |
|
1659 ec_slave_config_t *sc = NULL; |
|
1660 int ret = 0; |
|
1661 |
|
1662 if (unlikely(!ctx->requested)) { |
|
1663 ret = -EPERM; |
|
1664 goto out_return; |
|
1665 } |
|
1666 |
|
1667 if (down_interruptible(&master->master_sem)) { |
|
1668 ret = -EINTR; |
|
1669 goto out_return; |
|
1670 } |
|
1671 |
|
1672 if (config_index != 0xFFFFFFFF) { |
|
1673 if (!(sc = ec_master_get_config(master, config_index))) { |
|
1674 ret = -ENOENT; |
|
1675 goto out_up; |
|
1676 } |
|
1677 } |
|
1678 |
|
1679 ecrt_master_select_reference_clock(master, sc); |
|
1680 |
|
1681 out_up: |
|
1682 up(&master->master_sem); |
|
1683 out_return: |
|
1684 return ret; |
|
1685 } |
|
1686 |
|
1687 /*****************************************************************************/ |
|
1688 |
|
1689 /** Activates the master. |
|
1690 * |
|
1691 * \return Zero on success, otherwise a negative error code. |
|
1692 */ |
|
1693 static ATTRIBUTES int ec_ioctl_activate( |
|
1694 ec_master_t *master, /**< EtherCAT master. */ |
|
1695 void *arg, /**< ioctl() argument. */ |
|
1696 ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ |
|
1697 ) |
|
1698 { |
|
1699 ec_ioctl_master_activate_t io; |
|
1700 ec_domain_t *domain; |
|
1701 off_t offset; |
|
1702 int ret; |
|
1703 |
|
1704 if (unlikely(!ctx->requested)) |
|
1705 return -EPERM; |
|
1706 |
|
1707 io.process_data = NULL; |
|
1708 |
|
1709 /* Get the sum of the domains' process data sizes. */ |
|
1710 |
|
1711 ctx->process_data_size = 0; |
|
1712 |
|
1713 if (down_interruptible(&master->master_sem)) |
|
1714 return -EINTR; |
|
1715 |
|
1716 list_for_each_entry(domain, &master->domains, list) { |
|
1717 ctx->process_data_size += ecrt_domain_size(domain); |
|
1718 } |
|
1719 |
|
1720 up(&master->master_sem); |
|
1721 |
|
1722 if (ctx->process_data_size) { |
|
1723 ctx->process_data = vmalloc(ctx->process_data_size); |
|
1724 if (!ctx->process_data) { |
|
1725 ctx->process_data_size = 0; |
|
1726 return -ENOMEM; |
|
1727 } |
|
1728 |
|
1729 /* Set the memory as external process data memory for the |
|
1730 * domains. |
|
1731 */ |
|
1732 offset = 0; |
|
1733 list_for_each_entry(domain, &master->domains, list) { |
|
1734 ecrt_domain_external_memory(domain, |
|
1735 ctx->process_data + offset); |
|
1736 offset += ecrt_domain_size(domain); |
|
1737 } |
|
1738 |
|
1739 #ifdef EC_IOCTL_RTDM |
|
1740 /* RTDM uses a different approach for memory-mapping, which has to be |
|
1741 * initiated by the kernel. |
|
1742 */ |
|
1743 ret = ec_rtdm_mmap(ctx, &io.process_data); |
|
1744 if (ret < 0) { |
|
1745 EC_MASTER_ERR(master, "Failed to map process data" |
|
1746 " memory to user space (code %i).\n", ret); |
|
1747 return ret; |
|
1748 } |
|
1749 #endif |
|
1750 } |
|
1751 |
|
1752 io.process_data_size = ctx->process_data_size; |
|
1753 |
|
1754 #ifndef EC_IOCTL_RTDM |
|
1755 ecrt_master_callbacks(master, ec_master_internal_send_cb, |
|
1756 ec_master_internal_receive_cb, master); |
|
1757 #endif |
|
1758 |
|
1759 ret = ecrt_master_activate(master); |
|
1760 if (ret < 0) |
|
1761 return ret; |
|
1762 |
|
1763 if (copy_to_user((void __user *) arg, &io, |
|
1764 sizeof(ec_ioctl_master_activate_t))) |
|
1765 return -EFAULT; |
|
1766 |
|
1767 return 0; |
|
1768 } |
|
1769 |
|
1770 /*****************************************************************************/ |
|
1771 |
|
1772 /** Deactivates the master. |
|
1773 * |
|
1774 * \return Zero on success, otherwise a negative error code. |
|
1775 */ |
|
1776 static ATTRIBUTES int ec_ioctl_deactivate( |
|
1777 ec_master_t *master, /**< EtherCAT master. */ |
|
1778 void *arg, /**< ioctl() argument. */ |
|
1779 ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ |
|
1780 ) |
|
1781 { |
|
1782 if (unlikely(!ctx->requested)) |
|
1783 return -EPERM; |
|
1784 |
|
1785 ecrt_master_deactivate(master); |
|
1786 return 0; |
|
1787 } |
|
1788 |
|
1789 /*****************************************************************************/ |
|
1790 |
|
1791 /** Set max. number of databytes in a cycle |
|
1792 * |
|
1793 * \return Zero on success, otherwise a negative error code. |
|
1794 */ |
|
1795 static ATTRIBUTES int ec_ioctl_set_send_interval( |
|
1796 ec_master_t *master, /**< EtherCAT master. */ |
|
1797 void *arg, /**< ioctl() argument. */ |
|
1798 ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ |
|
1799 ) |
|
1800 { |
|
1801 size_t send_interval; |
|
1802 |
|
1803 if (unlikely(!ctx->requested)) { |
|
1804 return -EPERM; |
|
1805 } |
|
1806 |
|
1807 if (copy_from_user(&send_interval, (void __user *) arg, |
|
1808 sizeof(send_interval))) { |
|
1809 return -EFAULT; |
|
1810 } |
|
1811 |
|
1812 if (down_interruptible(&master->master_sem)) |
|
1813 return -EINTR; |
|
1814 |
|
1815 ec_master_set_send_interval(master, send_interval); |
|
1816 |
|
1817 up(&master->master_sem); |
|
1818 return 0; |
|
1819 } |
|
1820 |
|
1821 /*****************************************************************************/ |
|
1822 |
|
1823 /** Send frames. |
|
1824 * |
|
1825 * \return Zero on success, otherwise a negative error code. |
|
1826 */ |
|
1827 static ATTRIBUTES int ec_ioctl_send( |
|
1828 ec_master_t *master, /**< EtherCAT master. */ |
|
1829 void *arg, /**< ioctl() argument. */ |
|
1830 ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ |
|
1831 ) |
|
1832 { |
|
1833 if (unlikely(!ctx->requested)) { |
|
1834 return -EPERM; |
|
1835 } |
|
1836 |
|
1837 ecrt_master_send(master); |
|
1838 return 0; |
|
1839 } |
|
1840 |
|
1841 /*****************************************************************************/ |
|
1842 |
|
1843 /** Receive frames. |
|
1844 * |
|
1845 * \return Zero on success, otherwise a negative error code. |
|
1846 */ |
|
1847 static ATTRIBUTES int ec_ioctl_receive( |
|
1848 ec_master_t *master, /**< EtherCAT master. */ |
|
1849 void *arg, /**< ioctl() argument. */ |
|
1850 ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ |
|
1851 ) |
|
1852 { |
|
1853 if (unlikely(!ctx->requested)) { |
|
1854 return -EPERM; |
|
1855 } |
|
1856 |
|
1857 ecrt_master_receive(master); |
|
1858 return 0; |
|
1859 } |
|
1860 |
|
1861 /*****************************************************************************/ |
|
1862 |
|
1863 /** Get the master state. |
|
1864 * |
|
1865 * \return Zero on success, otherwise a negative error code. |
|
1866 */ |
|
1867 static ATTRIBUTES int ec_ioctl_master_state( |
|
1868 ec_master_t *master, /**< EtherCAT master. */ |
|
1869 void *arg, /**< ioctl() argument. */ |
|
1870 ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ |
|
1871 ) |
|
1872 { |
|
1873 ec_master_state_t data; |
|
1874 |
|
1875 ecrt_master_state(master, &data); |
|
1876 |
|
1877 if (copy_to_user((void __user *) arg, &data, sizeof(data))) |
|
1878 return -EFAULT; |
|
1879 |
|
1880 return 0; |
|
1881 } |
|
1882 |
|
1883 /*****************************************************************************/ |
|
1884 |
|
1885 /** Get the link state. |
|
1886 * |
|
1887 * \return Zero on success, otherwise a negative error code. |
|
1888 */ |
|
1889 static ATTRIBUTES int ec_ioctl_master_link_state( |
|
1890 ec_master_t *master, /**< EtherCAT master. */ |
|
1891 void *arg, /**< ioctl() argument. */ |
|
1892 ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ |
|
1893 ) |
|
1894 { |
|
1895 ec_ioctl_link_state_t ioctl; |
|
1896 ec_master_link_state_t state; |
|
1897 int ret; |
|
1898 |
|
1899 if (copy_from_user(&ioctl, (void __user *) arg, sizeof(ioctl))) { |
|
1900 return -EFAULT; |
|
1901 } |
|
1902 |
|
1903 ret = ecrt_master_link_state(master, ioctl.dev_idx, &state); |
|
1904 if (ret < 0) { |
|
1905 return ret; |
|
1906 } |
|
1907 |
|
1908 if (copy_to_user((void __user *) ioctl.state, &state, sizeof(state))) { |
|
1909 return -EFAULT; |
|
1910 } |
|
1911 |
|
1912 return 0; |
|
1913 } |
|
1914 |
|
1915 /*****************************************************************************/ |
|
1916 |
|
1917 /** Set the master DC application time. |
|
1918 * |
|
1919 * \return Zero on success, otherwise a negative error code. |
|
1920 */ |
|
1921 static ATTRIBUTES int ec_ioctl_app_time( |
|
1922 ec_master_t *master, /**< EtherCAT master. */ |
|
1923 void *arg, /**< ioctl() argument. */ |
|
1924 ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ |
|
1925 ) |
|
1926 { |
|
1927 ec_ioctl_app_time_t data; |
|
1928 |
|
1929 if (unlikely(!ctx->requested)) |
|
1930 return -EPERM; |
|
1931 |
|
1932 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { |
|
1933 return -EFAULT; |
|
1934 } |
|
1935 |
|
1936 ecrt_master_application_time(master, data.app_time); |
|
1937 return 0; |
|
1938 } |
|
1939 |
|
1940 /*****************************************************************************/ |
|
1941 |
|
1942 /** Sync the reference clock. |
|
1943 * |
|
1944 * \return Zero on success, otherwise a negative error code. |
|
1945 */ |
|
1946 static ATTRIBUTES int ec_ioctl_sync_ref( |
|
1947 ec_master_t *master, /**< EtherCAT master. */ |
|
1948 void *arg, /**< ioctl() argument. */ |
|
1949 ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ |
|
1950 ) |
|
1951 { |
|
1952 if (unlikely(!ctx->requested)) { |
|
1953 return -EPERM; |
|
1954 } |
|
1955 |
|
1956 ecrt_master_sync_reference_clock(master); |
|
1957 return 0; |
|
1958 } |
|
1959 |
|
1960 /*****************************************************************************/ |
|
1961 |
|
1962 /** Sync the slave clocks. |
|
1963 * |
|
1964 * \return Zero on success, otherwise a negative error code. |
|
1965 */ |
|
1966 static ATTRIBUTES int ec_ioctl_sync_slaves( |
|
1967 ec_master_t *master, /**< EtherCAT master. */ |
|
1968 void *arg, /**< ioctl() argument. */ |
|
1969 ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ |
|
1970 ) |
|
1971 { |
|
1972 if (unlikely(!ctx->requested)) { |
|
1973 return -EPERM; |
|
1974 } |
|
1975 |
|
1976 ecrt_master_sync_slave_clocks(master); |
|
1977 return 0; |
|
1978 } |
|
1979 |
|
1980 /*****************************************************************************/ |
|
1981 |
|
1982 /** Get the system time of the reference clock. |
|
1983 * |
|
1984 * \return Zero on success, otherwise a negative error code. |
|
1985 */ |
|
1986 static ATTRIBUTES int ec_ioctl_ref_clock_time( |
|
1987 ec_master_t *master, /**< EtherCAT master. */ |
|
1988 void *arg, /**< ioctl() argument. */ |
|
1989 ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ |
|
1990 ) |
|
1991 { |
|
1992 uint32_t time; |
|
1993 int ret; |
|
1994 |
|
1995 if (unlikely(!ctx->requested)) { |
|
1996 return -EPERM; |
|
1997 } |
|
1998 |
|
1999 ret = ecrt_master_reference_clock_time(master, &time); |
|
2000 if (ret) { |
|
2001 return ret; |
|
2002 } |
|
2003 |
|
2004 if (copy_to_user((void __user *) arg, &time, sizeof(time))) { |
|
2005 return -EFAULT; |
|
2006 } |
|
2007 |
|
2008 return 0; |
|
2009 } |
|
2010 |
|
2011 /*****************************************************************************/ |
|
2012 |
|
2013 /** Queue the sync monitoring datagram. |
|
2014 * |
|
2015 * \return Zero on success, otherwise a negative error code. |
|
2016 */ |
|
2017 static ATTRIBUTES int ec_ioctl_sync_mon_queue( |
|
2018 ec_master_t *master, /**< EtherCAT master. */ |
|
2019 void *arg, /**< ioctl() argument. */ |
|
2020 ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ |
|
2021 ) |
|
2022 { |
|
2023 if (unlikely(!ctx->requested)) { |
|
2024 return -EPERM; |
|
2025 } |
|
2026 |
|
2027 ecrt_master_sync_monitor_queue(master); |
|
2028 return 0; |
|
2029 } |
|
2030 |
|
2031 /*****************************************************************************/ |
|
2032 |
|
2033 /** Processes the sync monitoring datagram. |
|
2034 * |
|
2035 * \return Zero on success, otherwise a negative error code. |
|
2036 */ |
|
2037 static ATTRIBUTES int ec_ioctl_sync_mon_process( |
|
2038 ec_master_t *master, /**< EtherCAT master. */ |
|
2039 void *arg, /**< ioctl() argument. */ |
|
2040 ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ |
|
2041 ) |
|
2042 { |
|
2043 uint32_t time_diff; |
|
2044 |
|
2045 if (unlikely(!ctx->requested)) |
|
2046 return -EPERM; |
|
2047 |
|
2048 time_diff = ecrt_master_sync_monitor_process(master); |
|
2049 |
|
2050 if (copy_to_user((void __user *) arg, &time_diff, sizeof(time_diff))) |
|
2051 return -EFAULT; |
|
2052 |
|
2053 return 0; |
|
2054 } |
|
2055 |
|
2056 /*****************************************************************************/ |
|
2057 |
|
2058 /** Reset configuration. |
|
2059 * |
|
2060 * \return Always zero (success). |
|
2061 */ |
|
2062 static ATTRIBUTES int ec_ioctl_reset( |
|
2063 ec_master_t *master, /**< EtherCAT master. */ |
|
2064 void *arg, /**< ioctl() argument. */ |
|
2065 ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ |
|
2066 ) |
|
2067 { |
|
2068 down(&master->master_sem); |
|
2069 ecrt_master_reset(master); |
|
2070 up(&master->master_sem); |
|
2071 return 0; |
|
2072 } |
|
2073 |
|
2074 /*****************************************************************************/ |
|
2075 |
|
2076 /** Configure a sync manager. |
|
2077 * |
|
2078 * \return Zero on success, otherwise a negative error code. |
|
2079 */ |
|
2080 static ATTRIBUTES int ec_ioctl_sc_sync( |
|
2081 ec_master_t *master, /**< EtherCAT master. */ |
|
2082 void *arg, /**< ioctl() argument. */ |
|
2083 ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ |
|
2084 ) |
|
2085 { |
|
2086 ec_ioctl_config_t data; |
|
2087 ec_slave_config_t *sc; |
|
2088 unsigned int i; |
|
2089 int ret = 0; |
|
2090 |
|
2091 if (unlikely(!ctx->requested)) { |
|
2092 ret = -EPERM; |
|
2093 goto out_return; |
|
2094 } |
|
2095 |
|
2096 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { |
|
2097 ret = -EFAULT; |
|
2098 goto out_return; |
|
2099 } |
|
2100 |
|
2101 if (down_interruptible(&master->master_sem)) { |
|
2102 ret = -EINTR; |
|
2103 goto out_return; |
|
2104 } |
|
2105 |
|
2106 if (!(sc = ec_master_get_config(master, data.config_index))) { |
|
2107 ret = -ENOENT; |
|
2108 goto out_up; |
|
2109 } |
|
2110 |
|
2111 for (i = 0; i < EC_MAX_SYNC_MANAGERS; i++) { |
|
2112 if (data.syncs[i].config_this) { |
|
2113 ret = ecrt_slave_config_sync_manager(sc, i, data.syncs[i].dir, |
|
2114 data.syncs[i].watchdog_mode); |
|
2115 if (ret) { |
|
2116 goto out_up; |
|
2117 } |
|
2118 } |
|
2119 } |
|
2120 |
|
2121 out_up: |
|
2122 up(&master->master_sem); |
|
2123 out_return: |
|
2124 return ret; |
|
2125 } |
|
2126 |
|
2127 /*****************************************************************************/ |
|
2128 |
|
2129 /** Configure a slave's watchdogs. |
|
2130 * |
|
2131 * \return Zero on success, otherwise a negative error code. |
|
2132 */ |
|
2133 static ATTRIBUTES int ec_ioctl_sc_watchdog( |
|
2134 ec_master_t *master, /**< EtherCAT master. */ |
|
2135 void *arg, /**< ioctl() argument. */ |
|
2136 ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ |
|
2137 ) |
|
2138 { |
|
2139 ec_ioctl_config_t data; |
|
2140 ec_slave_config_t *sc; |
|
2141 int ret = 0; |
|
2142 |
|
2143 if (unlikely(!ctx->requested)) { |
|
2144 ret = -EPERM; |
|
2145 goto out_return; |
|
2146 } |
|
2147 |
|
2148 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { |
|
2149 ret = -EFAULT; |
|
2150 goto out_return; |
|
2151 } |
|
2152 |
|
2153 if (down_interruptible(&master->master_sem)) { |
|
2154 ret = -EINTR; |
|
2155 goto out_return; |
|
2156 } |
|
2157 |
|
2158 if (!(sc = ec_master_get_config(master, data.config_index))) { |
|
2159 ret = -ENOENT; |
|
2160 goto out_up; |
|
2161 } |
|
2162 |
|
2163 ecrt_slave_config_watchdog(sc, |
|
2164 data.watchdog_divider, data.watchdog_intervals); |
|
2165 |
|
2166 out_up: |
|
2167 up(&master->master_sem); |
|
2168 out_return: |
|
2169 return ret; |
|
2170 } |
|
2171 |
|
2172 /*****************************************************************************/ |
|
2173 |
|
2174 /** Add a PDO to the assignment. |
|
2175 * |
|
2176 * \return Zero on success, otherwise a negative error code. |
|
2177 */ |
|
2178 static ATTRIBUTES int ec_ioctl_sc_add_pdo( |
|
2179 ec_master_t *master, /**< EtherCAT master. */ |
|
2180 void *arg, /**< ioctl() argument. */ |
|
2181 ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ |
|
2182 ) |
|
2183 { |
|
2184 ec_ioctl_config_pdo_t data; |
|
2185 ec_slave_config_t *sc; |
|
2186 |
|
2187 if (unlikely(!ctx->requested)) |
|
2188 return -EPERM; |
|
2189 |
|
2190 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) |
|
2191 return -EFAULT; |
|
2192 |
|
2193 if (down_interruptible(&master->master_sem)) |
|
2194 return -EINTR; |
|
2195 |
|
2196 if (!(sc = ec_master_get_config(master, data.config_index))) { |
|
2197 up(&master->master_sem); |
|
2198 return -ENOENT; |
|
2199 } |
|
2200 |
|
2201 up(&master->master_sem); /** \todo sc could be invalidated */ |
|
2202 |
|
2203 return ecrt_slave_config_pdo_assign_add(sc, data.sync_index, data.index); |
|
2204 } |
|
2205 |
|
2206 /*****************************************************************************/ |
|
2207 |
|
2208 /** Clears the PDO assignment. |
|
2209 * |
|
2210 * \return Zero on success, otherwise a negative error code. |
|
2211 */ |
|
2212 static ATTRIBUTES int ec_ioctl_sc_clear_pdos( |
|
2213 ec_master_t *master, /**< EtherCAT master. */ |
|
2214 void *arg, /**< ioctl() argument. */ |
|
2215 ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ |
|
2216 ) |
|
2217 { |
|
2218 ec_ioctl_config_pdo_t data; |
|
2219 ec_slave_config_t *sc; |
|
2220 |
|
2221 if (unlikely(!ctx->requested)) |
|
2222 return -EPERM; |
|
2223 |
|
2224 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) |
|
2225 return -EFAULT; |
|
2226 |
|
2227 if (down_interruptible(&master->master_sem)) |
|
2228 return -EINTR; |
|
2229 |
|
2230 if (!(sc = ec_master_get_config(master, data.config_index))) { |
|
2231 up(&master->master_sem); |
|
2232 return -ENOENT; |
|
2233 } |
|
2234 |
|
2235 up(&master->master_sem); /** \todo sc could be invalidated */ |
|
2236 |
|
2237 ecrt_slave_config_pdo_assign_clear(sc, data.sync_index); |
|
2238 return 0; |
|
2239 } |
|
2240 |
|
2241 /*****************************************************************************/ |
|
2242 |
|
2243 /** Add an entry to a PDO's mapping. |
|
2244 * |
|
2245 * \return Zero on success, otherwise a negative error code. |
|
2246 */ |
|
2247 static ATTRIBUTES int ec_ioctl_sc_add_entry( |
|
2248 ec_master_t *master, /**< EtherCAT master. */ |
|
2249 void *arg, /**< ioctl() argument. */ |
|
2250 ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ |
|
2251 ) |
|
2252 { |
|
2253 ec_ioctl_add_pdo_entry_t data; |
|
2254 ec_slave_config_t *sc; |
|
2255 |
|
2256 if (unlikely(!ctx->requested)) |
|
2257 return -EPERM; |
|
2258 |
|
2259 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) |
|
2260 return -EFAULT; |
|
2261 |
|
2262 if (down_interruptible(&master->master_sem)) |
|
2263 return -EINTR; |
|
2264 |
|
2265 if (!(sc = ec_master_get_config(master, data.config_index))) { |
|
2266 up(&master->master_sem); |
|
2267 return -ENOENT; |
|
2268 } |
|
2269 |
|
2270 up(&master->master_sem); /** \todo sc could be invalidated */ |
|
2271 |
|
2272 return ecrt_slave_config_pdo_mapping_add(sc, data.pdo_index, |
|
2273 data.entry_index, data.entry_subindex, data.entry_bit_length); |
|
2274 } |
|
2275 |
|
2276 /*****************************************************************************/ |
|
2277 |
|
2278 /** Clears the mapping of a PDO. |
|
2279 * |
|
2280 * \return Zero on success, otherwise a negative error code. |
|
2281 */ |
|
2282 static ATTRIBUTES int ec_ioctl_sc_clear_entries( |
|
2283 ec_master_t *master, /**< EtherCAT master. */ |
|
2284 void *arg, /**< ioctl() argument. */ |
|
2285 ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ |
|
2286 ) |
|
2287 { |
|
2288 ec_ioctl_config_pdo_t data; |
|
2289 ec_slave_config_t *sc; |
|
2290 |
|
2291 if (unlikely(!ctx->requested)) |
|
2292 return -EPERM; |
|
2293 |
|
2294 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) |
|
2295 return -EFAULT; |
|
2296 |
|
2297 if (down_interruptible(&master->master_sem)) |
|
2298 return -EINTR; |
|
2299 |
|
2300 if (!(sc = ec_master_get_config(master, data.config_index))) { |
|
2301 up(&master->master_sem); |
|
2302 return -ENOENT; |
|
2303 } |
|
2304 |
|
2305 up(&master->master_sem); /** \todo sc could be invalidated */ |
|
2306 |
|
2307 ecrt_slave_config_pdo_mapping_clear(sc, data.index); |
|
2308 return 0; |
|
2309 } |
|
2310 |
|
2311 /*****************************************************************************/ |
|
2312 |
|
2313 /** Registers a PDO entry. |
|
2314 * |
|
2315 * \return Process data offset on success, otherwise a negative error code. |
|
2316 */ |
|
2317 static ATTRIBUTES int ec_ioctl_sc_reg_pdo_entry( |
|
2318 ec_master_t *master, /**< EtherCAT master. */ |
|
2319 void *arg, /**< ioctl() argument. */ |
|
2320 ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ |
|
2321 ) |
|
2322 { |
|
2323 ec_ioctl_reg_pdo_entry_t data; |
|
2324 ec_slave_config_t *sc; |
|
2325 ec_domain_t *domain; |
|
2326 int ret; |
|
2327 |
|
2328 if (unlikely(!ctx->requested)) |
|
2329 return -EPERM; |
|
2330 |
|
2331 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) |
|
2332 return -EFAULT; |
|
2333 |
|
2334 if (down_interruptible(&master->master_sem)) |
|
2335 return -EINTR; |
|
2336 |
|
2337 if (!(sc = ec_master_get_config(master, data.config_index))) { |
|
2338 up(&master->master_sem); |
|
2339 return -ENOENT; |
|
2340 } |
|
2341 |
|
2342 if (!(domain = ec_master_find_domain(master, data.domain_index))) { |
|
2343 up(&master->master_sem); |
|
2344 return -ENOENT; |
|
2345 } |
|
2346 |
|
2347 up(&master->master_sem); /** \todo sc or domain could be invalidated */ |
|
2348 |
|
2349 ret = ecrt_slave_config_reg_pdo_entry(sc, data.entry_index, |
|
2350 data.entry_subindex, domain, &data.bit_position); |
|
2351 |
|
2352 if (copy_to_user((void __user *) arg, &data, sizeof(data))) |
|
2353 return -EFAULT; |
|
2354 |
|
2355 return ret; |
|
2356 } |
|
2357 |
|
2358 /*****************************************************************************/ |
|
2359 |
|
2360 /** Registers a PDO entry by its position. |
|
2361 * |
|
2362 * \return Process data offset on success, otherwise a negative error code. |
|
2363 */ |
|
2364 static ATTRIBUTES int ec_ioctl_sc_reg_pdo_pos( |
|
2365 ec_master_t *master, /**< EtherCAT master. */ |
|
2366 void *arg, /**< ioctl() argument. */ |
|
2367 ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ |
|
2368 ) |
|
2369 { |
|
2370 ec_ioctl_reg_pdo_pos_t io; |
|
2371 ec_slave_config_t *sc; |
|
2372 ec_domain_t *domain; |
|
2373 int ret; |
|
2374 |
|
2375 if (unlikely(!ctx->requested)) { |
|
2376 return -EPERM; |
|
2377 } |
|
2378 |
|
2379 if (copy_from_user(&io, (void __user *) arg, sizeof(io))) { |
|
2380 return -EFAULT; |
|
2381 } |
|
2382 |
|
2383 if (down_interruptible(&master->master_sem)) { |
|
2384 return -EINTR; |
|
2385 } |
|
2386 |
|
2387 if (!(sc = ec_master_get_config(master, io.config_index))) { |
|
2388 up(&master->master_sem); |
|
2389 return -ENOENT; |
|
2390 } |
|
2391 |
|
2392 if (!(domain = ec_master_find_domain(master, io.domain_index))) { |
|
2393 up(&master->master_sem); |
|
2394 return -ENOENT; |
|
2395 } |
|
2396 |
|
2397 up(&master->master_sem); /** \todo sc or domain could be invalidated */ |
|
2398 |
|
2399 ret = ecrt_slave_config_reg_pdo_entry_pos(sc, io.sync_index, |
|
2400 io.pdo_pos, io.entry_pos, domain, &io.bit_position); |
|
2401 |
|
2402 if (copy_to_user((void __user *) arg, &io, sizeof(io))) |
|
2403 return -EFAULT; |
|
2404 |
|
2405 return ret; |
|
2406 } |
|
2407 |
|
2408 /*****************************************************************************/ |
|
2409 |
|
2410 /** Sets the DC AssignActivate word and the sync signal times. |
|
2411 * |
|
2412 * \return Zero on success, otherwise a negative error code. |
|
2413 */ |
|
2414 static ATTRIBUTES int ec_ioctl_sc_dc( |
|
2415 ec_master_t *master, /**< EtherCAT master. */ |
|
2416 void *arg, /**< ioctl() argument. */ |
|
2417 ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ |
|
2418 ) |
|
2419 { |
|
2420 ec_ioctl_config_t data; |
|
2421 ec_slave_config_t *sc; |
|
2422 |
|
2423 if (unlikely(!ctx->requested)) |
|
2424 return -EPERM; |
|
2425 |
|
2426 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) |
|
2427 return -EFAULT; |
|
2428 |
|
2429 if (down_interruptible(&master->master_sem)) |
|
2430 return -EINTR; |
|
2431 |
|
2432 if (!(sc = ec_master_get_config(master, data.config_index))) { |
|
2433 up(&master->master_sem); |
|
2434 return -ENOENT; |
|
2435 } |
|
2436 |
|
2437 ecrt_slave_config_dc(sc, data.dc_assign_activate, |
|
2438 data.dc_sync[0].cycle_time, |
|
2439 data.dc_sync[0].shift_time, |
|
2440 data.dc_sync[1].cycle_time, |
|
2441 data.dc_sync[1].shift_time); |
|
2442 |
|
2443 up(&master->master_sem); |
|
2444 |
|
2445 return 0; |
|
2446 } |
|
2447 |
|
2448 /*****************************************************************************/ |
|
2449 |
|
2450 /** Configures an SDO. |
|
2451 * |
|
2452 * \return Zero on success, otherwise a negative error code. |
|
2453 */ |
|
2454 static ATTRIBUTES int ec_ioctl_sc_sdo( |
|
2455 ec_master_t *master, /**< EtherCAT master. */ |
|
2456 void *arg, /**< ioctl() argument. */ |
|
2457 ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ |
|
2458 ) |
|
2459 { |
|
2460 ec_ioctl_sc_sdo_t data; |
|
2461 ec_slave_config_t *sc; |
|
2462 uint8_t *sdo_data = NULL; |
|
2463 int ret; |
|
2464 |
|
2465 if (unlikely(!ctx->requested)) |
|
2466 return -EPERM; |
|
2467 |
|
2468 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) |
|
2469 return -EFAULT; |
|
2470 |
|
2471 if (!data.size) |
|
2472 return -EINVAL; |
|
2473 |
|
2474 if (!(sdo_data = kmalloc(data.size, GFP_KERNEL))) { |
|
2475 return -ENOMEM; |
|
2476 } |
|
2477 |
|
2478 if (copy_from_user(sdo_data, (void __user *) data.data, data.size)) { |
|
2479 kfree(sdo_data); |
|
2480 return -EFAULT; |
|
2481 } |
|
2482 |
|
2483 if (down_interruptible(&master->master_sem)) { |
|
2484 kfree(sdo_data); |
|
2485 return -EINTR; |
|
2486 } |
|
2487 |
|
2488 if (!(sc = ec_master_get_config(master, data.config_index))) { |
|
2489 up(&master->master_sem); |
|
2490 kfree(sdo_data); |
|
2491 return -ENOENT; |
|
2492 } |
|
2493 |
|
2494 up(&master->master_sem); /** \todo sc could be invalidated */ |
|
2495 |
|
2496 if (data.complete_access) { |
|
2497 ret = ecrt_slave_config_complete_sdo(sc, |
|
2498 data.index, sdo_data, data.size); |
|
2499 } else { |
|
2500 ret = ecrt_slave_config_sdo(sc, data.index, data.subindex, sdo_data, |
|
2501 data.size); |
|
2502 } |
|
2503 kfree(sdo_data); |
|
2504 return ret; |
|
2505 } |
|
2506 |
|
2507 /*****************************************************************************/ |
|
2508 |
|
2509 /** Set the emergency ring buffer size. |
|
2510 * |
|
2511 * \return Zero on success, otherwise a negative error code. |
|
2512 */ |
|
2513 static ATTRIBUTES int ec_ioctl_sc_emerg_size( |
|
2514 ec_master_t *master, /**< EtherCAT master. */ |
|
2515 void *arg, /**< ioctl() argument. */ |
|
2516 ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ |
|
2517 ) |
|
2518 { |
|
2519 ec_ioctl_sc_emerg_t io; |
|
2520 ec_slave_config_t *sc; |
|
2521 int ret; |
|
2522 |
|
2523 if (unlikely(!ctx->requested)) |
|
2524 return -EPERM; |
|
2525 |
|
2526 if (copy_from_user(&io, (void __user *) arg, sizeof(io))) |
|
2527 return -EFAULT; |
|
2528 |
|
2529 if (down_interruptible(&master->master_sem)) { |
|
2530 return -EINTR; |
|
2531 } |
|
2532 |
|
2533 if (!(sc = ec_master_get_config(master, io.config_index))) { |
|
2534 up(&master->master_sem); |
|
2535 return -ENOENT; |
|
2536 } |
|
2537 |
|
2538 ret = ecrt_slave_config_emerg_size(sc, io.size); |
|
2539 |
|
2540 up(&master->master_sem); |
|
2541 |
|
2542 return ret; |
|
2543 } |
|
2544 |
|
2545 /*****************************************************************************/ |
|
2546 |
|
2547 /** Get an emergency message from the ring. |
|
2548 * |
|
2549 * \return Zero on success, otherwise a negative error code. |
|
2550 */ |
|
2551 static ATTRIBUTES int ec_ioctl_sc_emerg_pop( |
|
2552 ec_master_t *master, /**< EtherCAT master. */ |
|
2553 void *arg, /**< ioctl() argument. */ |
|
2554 ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ |
|
2555 ) |
|
2556 { |
|
2557 ec_ioctl_sc_emerg_t io; |
|
2558 ec_slave_config_t *sc; |
|
2559 u8 msg[EC_COE_EMERGENCY_MSG_SIZE]; |
|
2560 int ret; |
|
2561 |
|
2562 if (unlikely(!ctx->requested)) { |
|
2563 return -EPERM; |
|
2564 } |
|
2565 |
|
2566 if (copy_from_user(&io, (void __user *) arg, sizeof(io))) { |
|
2567 return -EFAULT; |
|
2568 } |
|
2569 |
|
2570 /* no locking of master_sem needed, because configuration will not be |
|
2571 * deleted in the meantime. */ |
|
2572 |
|
2573 if (!(sc = ec_master_get_config(master, io.config_index))) { |
|
2574 return -ENOENT; |
|
2575 } |
|
2576 |
|
2577 ret = ecrt_slave_config_emerg_pop(sc, msg); |
|
2578 if (ret < 0) { |
|
2579 return ret; |
|
2580 } |
|
2581 |
|
2582 if (copy_to_user((void __user *) io.target, msg, sizeof(msg))) { |
|
2583 return -EFAULT; |
|
2584 } |
|
2585 |
|
2586 return ret; |
|
2587 } |
|
2588 |
|
2589 /*****************************************************************************/ |
|
2590 |
|
2591 /** Clear the emergency ring. |
|
2592 * |
|
2593 * \return Zero on success, otherwise a negative error code. |
|
2594 */ |
|
2595 static ATTRIBUTES int ec_ioctl_sc_emerg_clear( |
|
2596 ec_master_t *master, /**< EtherCAT master. */ |
|
2597 void *arg, /**< ioctl() argument. */ |
|
2598 ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ |
|
2599 ) |
|
2600 { |
|
2601 ec_ioctl_sc_emerg_t io; |
|
2602 ec_slave_config_t *sc; |
|
2603 |
|
2604 if (unlikely(!ctx->requested)) { |
|
2605 return -EPERM; |
|
2606 } |
|
2607 |
|
2608 if (copy_from_user(&io, (void __user *) arg, sizeof(io))) { |
|
2609 return -EFAULT; |
|
2610 } |
|
2611 |
|
2612 /* no locking of master_sem needed, because configuration will not be |
|
2613 * deleted in the meantime. */ |
|
2614 |
|
2615 if (!(sc = ec_master_get_config(master, io.config_index))) { |
|
2616 return -ENOENT; |
|
2617 } |
|
2618 |
|
2619 return ecrt_slave_config_emerg_clear(sc); |
|
2620 } |
|
2621 |
|
2622 /*****************************************************************************/ |
|
2623 |
|
2624 /** Get the number of emergency overruns. |
|
2625 * |
|
2626 * \return Zero on success, otherwise a negative error code. |
|
2627 */ |
|
2628 static ATTRIBUTES int ec_ioctl_sc_emerg_overruns( |
|
2629 ec_master_t *master, /**< EtherCAT master. */ |
|
2630 void *arg, /**< ioctl() argument. */ |
|
2631 ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ |
|
2632 ) |
|
2633 { |
|
2634 ec_ioctl_sc_emerg_t io; |
|
2635 ec_slave_config_t *sc; |
|
2636 int ret; |
|
2637 |
|
2638 if (unlikely(!ctx->requested)) { |
|
2639 return -EPERM; |
|
2640 } |
|
2641 |
|
2642 if (copy_from_user(&io, (void __user *) arg, sizeof(io))) { |
|
2643 return -EFAULT; |
|
2644 } |
|
2645 |
|
2646 /* no locking of master_sem needed, because configuration will not be |
|
2647 * deleted in the meantime. */ |
|
2648 |
|
2649 if (!(sc = ec_master_get_config(master, io.config_index))) { |
|
2650 return -ENOENT; |
|
2651 } |
|
2652 |
|
2653 ret = ecrt_slave_config_emerg_overruns(sc); |
|
2654 if (ret < 0) { |
|
2655 return ret; |
|
2656 } |
|
2657 |
|
2658 io.overruns = ret; |
|
2659 |
|
2660 if (copy_to_user((void __user *) arg, &io, sizeof(io))) { |
|
2661 return -EFAULT; |
|
2662 } |
|
2663 |
|
2664 return 0; |
|
2665 } |
|
2666 |
|
2667 /*****************************************************************************/ |
|
2668 |
|
2669 /** Create an SDO request. |
|
2670 * |
|
2671 * \return Zero on success, otherwise a negative error code. |
|
2672 */ |
|
2673 static ATTRIBUTES int ec_ioctl_sc_create_sdo_request( |
|
2674 ec_master_t *master, /**< EtherCAT master. */ |
|
2675 void *arg, /**< ioctl() argument. */ |
|
2676 ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ |
|
2677 ) |
|
2678 { |
|
2679 ec_ioctl_sdo_request_t data; |
|
2680 ec_slave_config_t *sc; |
|
2681 ec_sdo_request_t *req; |
|
2682 |
|
2683 if (unlikely(!ctx->requested)) |
|
2684 return -EPERM; |
|
2685 |
|
2686 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { |
|
2687 return -EFAULT; |
|
2688 } |
|
2689 |
|
2690 data.request_index = 0; |
|
2691 |
|
2692 if (down_interruptible(&master->master_sem)) |
|
2693 return -EINTR; |
|
2694 |
|
2695 sc = ec_master_get_config(master, data.config_index); |
|
2696 if (!sc) { |
|
2697 up(&master->master_sem); |
|
2698 return -ENOENT; |
|
2699 } |
|
2700 |
|
2701 list_for_each_entry(req, &sc->sdo_requests, list) { |
|
2702 data.request_index++; |
|
2703 } |
|
2704 |
|
2705 up(&master->master_sem); /** \todo sc could be invalidated */ |
|
2706 |
|
2707 req = ecrt_slave_config_create_sdo_request_err(sc, data.sdo_index, |
|
2708 data.sdo_subindex, data.size); |
|
2709 if (IS_ERR(req)) |
|
2710 return PTR_ERR(req); |
|
2711 |
|
2712 if (copy_to_user((void __user *) arg, &data, sizeof(data))) |
|
2713 return -EFAULT; |
|
2714 |
|
2715 return 0; |
|
2716 } |
|
2717 |
|
2718 /*****************************************************************************/ |
|
2719 |
|
2720 /** Create a register request. |
|
2721 * |
|
2722 * \return Zero on success, otherwise a negative error code. |
|
2723 */ |
|
2724 static ATTRIBUTES int ec_ioctl_sc_create_reg_request( |
|
2725 ec_master_t *master, /**< EtherCAT master. */ |
|
2726 void *arg, /**< ioctl() argument. */ |
|
2727 ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ |
|
2728 ) |
|
2729 { |
|
2730 ec_ioctl_reg_request_t io; |
|
2731 ec_slave_config_t *sc; |
|
2732 ec_reg_request_t *reg; |
|
2733 |
|
2734 if (unlikely(!ctx->requested)) { |
|
2735 return -EPERM; |
|
2736 } |
|
2737 |
|
2738 if (copy_from_user(&io, (void __user *) arg, sizeof(io))) { |
|
2739 return -EFAULT; |
|
2740 } |
|
2741 |
|
2742 io.request_index = 0; |
|
2743 |
|
2744 if (down_interruptible(&master->master_sem)) { |
|
2745 return -EINTR; |
|
2746 } |
|
2747 |
|
2748 sc = ec_master_get_config(master, io.config_index); |
|
2749 if (!sc) { |
|
2750 up(&master->master_sem); |
|
2751 return -ENOENT; |
|
2752 } |
|
2753 |
|
2754 list_for_each_entry(reg, &sc->reg_requests, list) { |
|
2755 io.request_index++; |
|
2756 } |
|
2757 |
|
2758 up(&master->master_sem); /** \todo sc could be invalidated */ |
|
2759 |
|
2760 reg = ecrt_slave_config_create_reg_request_err(sc, io.mem_size); |
|
2761 if (IS_ERR(reg)) { |
|
2762 return PTR_ERR(reg); |
|
2763 } |
|
2764 |
|
2765 if (copy_to_user((void __user *) arg, &io, sizeof(io))) { |
|
2766 return -EFAULT; |
|
2767 } |
|
2768 |
|
2769 return 0; |
|
2770 } |
|
2771 |
|
2772 /*****************************************************************************/ |
|
2773 |
|
2774 /** Create a VoE handler. |
|
2775 * |
|
2776 * \return Zero on success, otherwise a negative error code. |
|
2777 */ |
|
2778 static ATTRIBUTES int ec_ioctl_sc_create_voe_handler( |
|
2779 ec_master_t *master, /**< EtherCAT master. */ |
|
2780 void *arg, /**< ioctl() argument. */ |
|
2781 ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ |
|
2782 ) |
|
2783 { |
|
2784 ec_ioctl_voe_t data; |
|
2785 ec_slave_config_t *sc; |
|
2786 ec_voe_handler_t *voe; |
|
2787 |
|
2788 if (unlikely(!ctx->requested)) |
|
2789 return -EPERM; |
|
2790 |
|
2791 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { |
|
2792 return -EFAULT; |
|
2793 } |
|
2794 |
|
2795 data.voe_index = 0; |
|
2796 |
|
2797 if (down_interruptible(&master->master_sem)) |
|
2798 return -EINTR; |
|
2799 |
|
2800 sc = ec_master_get_config(master, data.config_index); |
|
2801 if (!sc) { |
|
2802 up(&master->master_sem); |
|
2803 return -ENOENT; |
|
2804 } |
|
2805 |
|
2806 list_for_each_entry(voe, &sc->voe_handlers, list) { |
|
2807 data.voe_index++; |
|
2808 } |
|
2809 |
|
2810 up(&master->master_sem); /** \todo sc could be invalidated */ |
|
2811 |
|
2812 voe = ecrt_slave_config_create_voe_handler_err(sc, data.size); |
|
2813 if (IS_ERR(voe)) |
|
2814 return PTR_ERR(voe); |
|
2815 |
|
2816 if (copy_to_user((void __user *) arg, &data, sizeof(data))) |
|
2817 return -EFAULT; |
|
2818 |
|
2819 return 0; |
|
2820 } |
|
2821 |
|
2822 /*****************************************************************************/ |
|
2823 |
|
2824 /** Get the slave configuration's state. |
|
2825 * |
|
2826 * \return Zero on success, otherwise a negative error code. |
|
2827 */ |
|
2828 static ATTRIBUTES int ec_ioctl_sc_state( |
|
2829 ec_master_t *master, /**< EtherCAT master. */ |
|
2830 void *arg, /**< ioctl() argument. */ |
|
2831 ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ |
|
2832 ) |
|
2833 { |
|
2834 ec_ioctl_sc_state_t data; |
|
2835 const ec_slave_config_t *sc; |
|
2836 ec_slave_config_state_t state; |
|
2837 |
|
2838 if (unlikely(!ctx->requested)) |
|
2839 return -EPERM; |
|
2840 |
|
2841 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { |
|
2842 return -EFAULT; |
|
2843 } |
|
2844 |
|
2845 /* no locking of master_sem needed, because sc will not be deleted in the |
|
2846 * meantime. */ |
|
2847 |
|
2848 if (!(sc = ec_master_get_config_const(master, data.config_index))) { |
|
2849 return -ENOENT; |
|
2850 } |
|
2851 |
|
2852 ecrt_slave_config_state(sc, &state); |
|
2853 |
|
2854 if (copy_to_user((void __user *) data.state, &state, sizeof(state))) |
|
2855 return -EFAULT; |
|
2856 |
|
2857 return 0; |
|
2858 } |
|
2859 |
|
2860 /*****************************************************************************/ |
|
2861 |
|
2862 /** Configures an IDN. |
|
2863 * |
|
2864 * \return Zero on success, otherwise a negative error code. |
|
2865 */ |
|
2866 static ATTRIBUTES int ec_ioctl_sc_idn( |
|
2867 ec_master_t *master, /**< EtherCAT master. */ |
|
2868 void *arg, /**< ioctl() argument. */ |
|
2869 ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ |
|
2870 ) |
|
2871 { |
|
2872 ec_ioctl_sc_idn_t ioctl; |
|
2873 ec_slave_config_t *sc; |
|
2874 uint8_t *data = NULL; |
|
2875 int ret; |
|
2876 |
|
2877 if (unlikely(!ctx->requested)) |
|
2878 return -EPERM; |
|
2879 |
|
2880 if (copy_from_user(&ioctl, (void __user *) arg, sizeof(ioctl))) |
|
2881 return -EFAULT; |
|
2882 |
|
2883 if (!ioctl.size) |
|
2884 return -EINVAL; |
|
2885 |
|
2886 if (!(data = kmalloc(ioctl.size, GFP_KERNEL))) { |
|
2887 return -ENOMEM; |
|
2888 } |
|
2889 |
|
2890 if (copy_from_user(data, (void __user *) ioctl.data, ioctl.size)) { |
|
2891 kfree(data); |
|
2892 return -EFAULT; |
|
2893 } |
|
2894 |
|
2895 if (down_interruptible(&master->master_sem)) { |
|
2896 kfree(data); |
|
2897 return -EINTR; |
|
2898 } |
|
2899 |
|
2900 if (!(sc = ec_master_get_config(master, ioctl.config_index))) { |
|
2901 up(&master->master_sem); |
|
2902 kfree(data); |
|
2903 return -ENOENT; |
|
2904 } |
|
2905 |
|
2906 up(&master->master_sem); /** \todo sc could be invalidated */ |
|
2907 |
|
2908 ret = ecrt_slave_config_idn( |
|
2909 sc, ioctl.drive_no, ioctl.idn, ioctl.al_state, data, ioctl.size); |
|
2910 kfree(data); |
|
2911 return ret; |
|
2912 } |
|
2913 |
|
2914 /*****************************************************************************/ |
|
2915 |
|
2916 /** Gets the domain's data size. |
|
2917 * |
|
2918 * \return Domain size, or a negative error code. |
|
2919 */ |
|
2920 static ATTRIBUTES int ec_ioctl_domain_size( |
|
2921 ec_master_t *master, /**< EtherCAT master. */ |
|
2922 void *arg, /**< ioctl() argument. */ |
|
2923 ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ |
|
2924 ) |
|
2925 { |
|
2926 const ec_domain_t *domain; |
|
2927 |
|
2928 if (unlikely(!ctx->requested)) { |
|
2929 return -EPERM; |
|
2930 } |
|
2931 |
|
2932 if (down_interruptible(&master->master_sem)) { |
|
2933 return -EINTR; |
|
2934 } |
|
2935 |
|
2936 list_for_each_entry(domain, &master->domains, list) { |
|
2937 if (domain->index == (unsigned long) arg) { |
|
2938 size_t size = ecrt_domain_size(domain); |
|
2939 up(&master->master_sem); |
|
2940 return size; |
|
2941 } |
|
2942 } |
|
2943 |
|
2944 up(&master->master_sem); |
|
2945 return -ENOENT; |
|
2946 } |
|
2947 |
|
2948 /*****************************************************************************/ |
|
2949 |
|
2950 /** Gets the domain's offset in the total process data. |
|
2951 * |
|
2952 * \return Domain offset, or a negative error code. |
|
2953 */ |
|
2954 static ATTRIBUTES int ec_ioctl_domain_offset( |
|
2955 ec_master_t *master, /**< EtherCAT master. */ |
|
2956 void *arg, /**< ioctl() argument. */ |
|
2957 ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ |
|
2958 ) |
|
2959 { |
|
2960 int offset = 0; |
|
2961 const ec_domain_t *domain; |
|
2962 |
|
2963 if (unlikely(!ctx->requested)) |
|
2964 return -EPERM; |
|
2965 |
|
2966 if (down_interruptible(&master->master_sem)) { |
|
2967 return -EINTR; |
|
2968 } |
|
2969 |
|
2970 list_for_each_entry(domain, &master->domains, list) { |
|
2971 if (domain->index == (unsigned long) arg) { |
|
2972 up(&master->master_sem); |
|
2973 return offset; |
|
2974 } |
|
2975 offset += ecrt_domain_size(domain); |
|
2976 } |
|
2977 |
|
2978 up(&master->master_sem); |
|
2979 return -ENOENT; |
|
2980 } |
|
2981 |
|
2982 /*****************************************************************************/ |
|
2983 |
|
2984 /** Process the domain. |
|
2985 * |
|
2986 * \return Zero on success, otherwise a negative error code. |
|
2987 */ |
|
2988 static ATTRIBUTES int ec_ioctl_domain_process( |
|
2989 ec_master_t *master, /**< EtherCAT master. */ |
|
2990 void *arg, /**< ioctl() argument. */ |
|
2991 ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ |
|
2992 ) |
|
2993 { |
|
2994 ec_domain_t *domain; |
|
2995 |
|
2996 if (unlikely(!ctx->requested)) |
|
2997 return -EPERM; |
|
2998 |
|
2999 /* no locking of master_sem needed, because domain will not be deleted in |
|
3000 * the meantime. */ |
|
3001 |
|
3002 if (!(domain = ec_master_find_domain(master, (unsigned long) arg))) { |
|
3003 return -ENOENT; |
|
3004 } |
|
3005 |
|
3006 ecrt_domain_process(domain); |
|
3007 return 0; |
|
3008 } |
|
3009 |
|
3010 /*****************************************************************************/ |
|
3011 |
|
3012 /** Queue the domain. |
|
3013 * |
|
3014 * \return Zero on success, otherwise a negative error code. |
|
3015 */ |
|
3016 static ATTRIBUTES int ec_ioctl_domain_queue( |
|
3017 ec_master_t *master, /**< EtherCAT master. */ |
|
3018 void *arg, /**< ioctl() argument. */ |
|
3019 ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ |
|
3020 ) |
|
3021 { |
|
3022 ec_domain_t *domain; |
|
3023 |
|
3024 if (unlikely(!ctx->requested)) |
|
3025 return -EPERM; |
|
3026 |
|
3027 /* no locking of master_sem needed, because domain will not be deleted in |
|
3028 * the meantime. */ |
|
3029 |
|
3030 if (!(domain = ec_master_find_domain(master, (unsigned long) arg))) { |
|
3031 return -ENOENT; |
|
3032 } |
|
3033 |
|
3034 ecrt_domain_queue(domain); |
|
3035 return 0; |
|
3036 } |
|
3037 |
|
3038 /*****************************************************************************/ |
|
3039 |
|
3040 /** Get the domain state. |
|
3041 * |
|
3042 * \return Zero on success, otherwise a negative error code. |
|
3043 */ |
|
3044 static ATTRIBUTES int ec_ioctl_domain_state( |
|
3045 ec_master_t *master, /**< EtherCAT master. */ |
|
3046 void *arg, /**< ioctl() argument. */ |
|
3047 ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ |
|
3048 ) |
|
3049 { |
|
3050 ec_ioctl_domain_state_t data; |
|
3051 const ec_domain_t *domain; |
|
3052 ec_domain_state_t state; |
|
3053 |
|
3054 if (unlikely(!ctx->requested)) |
|
3055 return -EPERM; |
|
3056 |
|
3057 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { |
|
3058 return -EFAULT; |
|
3059 } |
|
3060 |
|
3061 /* no locking of master_sem needed, because domain will not be deleted in |
|
3062 * the meantime. */ |
|
3063 |
|
3064 if (!(domain = ec_master_find_domain_const(master, data.domain_index))) { |
|
3065 return -ENOENT; |
|
3066 } |
|
3067 |
|
3068 ecrt_domain_state(domain, &state); |
|
3069 |
|
3070 if (copy_to_user((void __user *) data.state, &state, sizeof(state))) |
|
3071 return -EFAULT; |
|
3072 |
|
3073 return 0; |
|
3074 } |
|
3075 |
|
3076 /*****************************************************************************/ |
|
3077 |
|
3078 /** Sets an SDO request's SDO index and subindex. |
|
3079 * |
|
3080 * \return Zero on success, otherwise a negative error code. |
|
3081 */ |
|
3082 static ATTRIBUTES int ec_ioctl_sdo_request_index( |
|
3083 ec_master_t *master, /**< EtherCAT master. */ |
|
3084 void *arg, /**< ioctl() argument. */ |
|
3085 ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ |
|
3086 ) |
|
3087 { |
|
3088 ec_ioctl_sdo_request_t data; |
|
3089 ec_slave_config_t *sc; |
|
3090 ec_sdo_request_t *req; |
|
3091 |
|
3092 if (unlikely(!ctx->requested)) |
|
3093 return -EPERM; |
|
3094 |
|
3095 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) |
|
3096 return -EFAULT; |
|
3097 |
|
3098 /* no locking of master_sem needed, because neither sc nor req will not be |
|
3099 * deleted in the meantime. */ |
|
3100 |
|
3101 if (!(sc = ec_master_get_config(master, data.config_index))) { |
|
3102 return -ENOENT; |
|
3103 } |
|
3104 |
|
3105 if (!(req = ec_slave_config_find_sdo_request(sc, data.request_index))) { |
|
3106 return -ENOENT; |
|
3107 } |
|
3108 |
|
3109 ecrt_sdo_request_index(req, data.sdo_index, data.sdo_subindex); |
|
3110 return 0; |
|
3111 } |
|
3112 |
|
3113 /*****************************************************************************/ |
|
3114 |
|
3115 /** Sets an SDO request's timeout. |
|
3116 * |
|
3117 * \return Zero on success, otherwise a negative error code. |
|
3118 */ |
|
3119 static ATTRIBUTES int ec_ioctl_sdo_request_timeout( |
|
3120 ec_master_t *master, /**< EtherCAT master. */ |
|
3121 void *arg, /**< ioctl() argument. */ |
|
3122 ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ |
|
3123 ) |
|
3124 { |
|
3125 ec_ioctl_sdo_request_t data; |
|
3126 ec_slave_config_t *sc; |
|
3127 ec_sdo_request_t *req; |
|
3128 |
|
3129 if (unlikely(!ctx->requested)) |
|
3130 return -EPERM; |
|
3131 |
|
3132 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) |
|
3133 return -EFAULT; |
|
3134 |
|
3135 /* no locking of master_sem needed, because neither sc nor req will not be |
|
3136 * deleted in the meantime. */ |
|
3137 |
|
3138 if (!(sc = ec_master_get_config(master, data.config_index))) { |
|
3139 return -ENOENT; |
|
3140 } |
|
3141 |
|
3142 if (!(req = ec_slave_config_find_sdo_request(sc, data.request_index))) { |
|
3143 return -ENOENT; |
|
3144 } |
|
3145 |
|
3146 ecrt_sdo_request_timeout(req, data.timeout); |
|
3147 return 0; |
|
3148 } |
|
3149 |
|
3150 /*****************************************************************************/ |
|
3151 |
|
3152 /** Gets an SDO request's state. |
|
3153 * |
|
3154 * \return Zero on success, otherwise a negative error code. |
|
3155 */ |
|
3156 static ATTRIBUTES int ec_ioctl_sdo_request_state( |
|
3157 ec_master_t *master, /**< EtherCAT master. */ |
|
3158 void *arg, /**< ioctl() argument. */ |
|
3159 ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ |
|
3160 ) |
|
3161 { |
|
3162 ec_ioctl_sdo_request_t data; |
|
3163 ec_slave_config_t *sc; |
|
3164 ec_sdo_request_t *req; |
|
3165 |
|
3166 if (unlikely(!ctx->requested)) |
|
3167 return -EPERM; |
|
3168 |
|
3169 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) |
|
3170 return -EFAULT; |
|
3171 |
|
3172 /* no locking of master_sem needed, because neither sc nor req will not be |
|
3173 * deleted in the meantime. */ |
|
3174 |
|
3175 if (!(sc = ec_master_get_config(master, data.config_index))) { |
|
3176 return -ENOENT; |
|
3177 } |
|
3178 |
|
3179 if (!(req = ec_slave_config_find_sdo_request(sc, data.request_index))) { |
|
3180 return -ENOENT; |
|
3181 } |
|
3182 |
|
3183 data.state = ecrt_sdo_request_state(req); |
|
3184 if (data.state == EC_REQUEST_SUCCESS && req->dir == EC_DIR_INPUT) |
|
3185 data.size = ecrt_sdo_request_data_size(req); |
|
3186 else |
|
3187 data.size = 0; |
|
3188 |
|
3189 if (copy_to_user((void __user *) arg, &data, sizeof(data))) |
|
3190 return -EFAULT; |
|
3191 |
|
3192 return 0; |
|
3193 } |
|
3194 |
|
3195 /*****************************************************************************/ |
|
3196 |
|
3197 /** Starts an SDO read operation. |
|
3198 * |
|
3199 * \return Zero on success, otherwise a negative error code. |
|
3200 */ |
|
3201 static ATTRIBUTES int ec_ioctl_sdo_request_read( |
|
3202 ec_master_t *master, /**< EtherCAT master. */ |
|
3203 void *arg, /**< ioctl() argument. */ |
|
3204 ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ |
|
3205 ) |
|
3206 { |
|
3207 ec_ioctl_sdo_request_t data; |
|
3208 ec_slave_config_t *sc; |
|
3209 ec_sdo_request_t *req; |
|
3210 |
|
3211 if (unlikely(!ctx->requested)) |
|
3212 return -EPERM; |
|
3213 |
|
3214 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) |
|
3215 return -EFAULT; |
|
3216 |
|
3217 /* no locking of master_sem needed, because neither sc nor req will not be |
|
3218 * deleted in the meantime. */ |
|
3219 |
|
3220 if (!(sc = ec_master_get_config(master, data.config_index))) { |
|
3221 return -ENOENT; |
|
3222 } |
|
3223 |
|
3224 if (!(req = ec_slave_config_find_sdo_request(sc, data.request_index))) { |
|
3225 return -ENOENT; |
|
3226 } |
|
3227 |
|
3228 ecrt_sdo_request_read(req); |
|
3229 return 0; |
|
3230 } |
|
3231 |
|
3232 /*****************************************************************************/ |
|
3233 |
|
3234 /** Starts an SDO write operation. |
|
3235 * |
|
3236 * \return Zero on success, otherwise a negative error code. |
|
3237 */ |
|
3238 static ATTRIBUTES int ec_ioctl_sdo_request_write( |
|
3239 ec_master_t *master, /**< EtherCAT master. */ |
|
3240 void *arg, /**< ioctl() argument. */ |
|
3241 ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ |
|
3242 ) |
|
3243 { |
|
3244 ec_ioctl_sdo_request_t data; |
|
3245 ec_slave_config_t *sc; |
|
3246 ec_sdo_request_t *req; |
|
3247 int ret; |
|
3248 |
|
3249 if (unlikely(!ctx->requested)) |
|
3250 return -EPERM; |
|
3251 |
|
3252 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) |
|
3253 return -EFAULT; |
|
3254 |
|
3255 if (!data.size) { |
|
3256 EC_MASTER_ERR(master, "SDO download: Data size may not be zero!\n"); |
|
3257 return -EINVAL; |
|
3258 } |
|
3259 |
|
3260 /* no locking of master_sem needed, because neither sc nor req will not be |
|
3261 * deleted in the meantime. */ |
|
3262 |
|
3263 if (!(sc = ec_master_get_config(master, data.config_index))) { |
|
3264 return -ENOENT; |
|
3265 } |
|
3266 |
|
3267 if (!(req = ec_slave_config_find_sdo_request(sc, data.request_index))) { |
|
3268 return -ENOENT; |
|
3269 } |
|
3270 |
|
3271 ret = ec_sdo_request_alloc(req, data.size); |
|
3272 if (ret) |
|
3273 return ret; |
|
3274 |
|
3275 if (copy_from_user(req->data, (void __user *) data.data, data.size)) |
|
3276 return -EFAULT; |
|
3277 |
|
3278 req->data_size = data.size; |
|
3279 ecrt_sdo_request_write(req); |
|
3280 return 0; |
|
3281 } |
|
3282 |
|
3283 /*****************************************************************************/ |
|
3284 |
|
3285 /** Read SDO data. |
|
3286 * |
|
3287 * \return Zero on success, otherwise a negative error code. |
|
3288 */ |
|
3289 static ATTRIBUTES int ec_ioctl_sdo_request_data( |
|
3290 ec_master_t *master, /**< EtherCAT master. */ |
|
3291 void *arg, /**< ioctl() argument. */ |
|
3292 ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ |
|
3293 ) |
|
3294 { |
|
3295 ec_ioctl_sdo_request_t data; |
|
3296 ec_slave_config_t *sc; |
|
3297 ec_sdo_request_t *req; |
|
3298 |
|
3299 if (unlikely(!ctx->requested)) |
|
3300 return -EPERM; |
|
3301 |
|
3302 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) |
|
3303 return -EFAULT; |
|
3304 |
|
3305 /* no locking of master_sem needed, because neither sc nor req will not be |
|
3306 * deleted in the meantime. */ |
|
3307 |
|
3308 if (!(sc = ec_master_get_config(master, data.config_index))) { |
|
3309 return -ENOENT; |
|
3310 } |
|
3311 |
|
3312 if (!(req = ec_slave_config_find_sdo_request(sc, data.request_index))) { |
|
3313 return -ENOENT; |
|
3314 } |
|
3315 |
|
3316 if (copy_to_user((void __user *) data.data, ecrt_sdo_request_data(req), |
|
3317 ecrt_sdo_request_data_size(req))) |
|
3318 return -EFAULT; |
|
3319 |
|
3320 return 0; |
|
3321 } |
|
3322 |
|
3323 /*****************************************************************************/ |
|
3324 |
|
3325 /** Read register data. |
|
3326 * |
|
3327 * \return Zero on success, otherwise a negative error code. |
|
3328 */ |
|
3329 static ATTRIBUTES int ec_ioctl_reg_request_data( |
|
3330 ec_master_t *master, /**< EtherCAT master. */ |
|
3331 void *arg, /**< ioctl() argument. */ |
|
3332 ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ |
|
3333 ) |
|
3334 { |
|
3335 ec_ioctl_reg_request_t io; |
|
3336 ec_slave_config_t *sc; |
|
3337 ec_reg_request_t *reg; |
|
3338 |
|
3339 if (unlikely(!ctx->requested)) { |
|
3340 return -EPERM; |
|
3341 } |
|
3342 |
|
3343 if (copy_from_user(&io, (void __user *) arg, sizeof(io))) { |
|
3344 return -EFAULT; |
|
3345 } |
|
3346 |
|
3347 if (io.mem_size <= 0) { |
|
3348 return 0; |
|
3349 } |
|
3350 |
|
3351 /* no locking of master_sem needed, because neither sc nor reg will not be |
|
3352 * deleted in the meantime. */ |
|
3353 |
|
3354 if (!(sc = ec_master_get_config(master, io.config_index))) { |
|
3355 return -ENOENT; |
|
3356 } |
|
3357 |
|
3358 if (!(reg = ec_slave_config_find_reg_request(sc, io.request_index))) { |
|
3359 return -ENOENT; |
|
3360 } |
|
3361 |
|
3362 if (copy_to_user((void __user *) io.data, ecrt_reg_request_data(reg), |
|
3363 min(reg->mem_size, io.mem_size))) { |
|
3364 return -EFAULT; |
|
3365 } |
|
3366 |
|
3367 return 0; |
|
3368 } |
|
3369 |
|
3370 /*****************************************************************************/ |
|
3371 |
|
3372 /** Gets an register request's state. |
|
3373 * |
|
3374 * \return Zero on success, otherwise a negative error code. |
|
3375 */ |
|
3376 static ATTRIBUTES int ec_ioctl_reg_request_state( |
|
3377 ec_master_t *master, /**< EtherCAT master. */ |
|
3378 void *arg, /**< ioctl() argument. */ |
|
3379 ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ |
|
3380 ) |
|
3381 { |
|
3382 ec_ioctl_reg_request_t io; |
|
3383 ec_slave_config_t *sc; |
|
3384 ec_reg_request_t *reg; |
|
3385 |
|
3386 if (unlikely(!ctx->requested)) { |
|
3387 return -EPERM; |
|
3388 } |
|
3389 |
|
3390 if (copy_from_user(&io, (void __user *) arg, sizeof(io))) { |
|
3391 return -EFAULT; |
|
3392 } |
|
3393 |
|
3394 /* no locking of master_sem needed, because neither sc nor reg will not be |
|
3395 * deleted in the meantime. */ |
|
3396 |
|
3397 if (!(sc = ec_master_get_config(master, io.config_index))) { |
|
3398 return -ENOENT; |
|
3399 } |
|
3400 |
|
3401 if (!(reg = ec_slave_config_find_reg_request(sc, io.request_index))) { |
|
3402 return -ENOENT; |
|
3403 } |
|
3404 |
|
3405 io.state = ecrt_reg_request_state(reg); |
|
3406 io.new_data = io.state == EC_REQUEST_SUCCESS && reg->dir == EC_DIR_INPUT; |
|
3407 |
|
3408 if (copy_to_user((void __user *) arg, &io, sizeof(io))) { |
|
3409 return -EFAULT; |
|
3410 } |
|
3411 |
|
3412 return 0; |
|
3413 } |
|
3414 |
|
3415 /*****************************************************************************/ |
|
3416 |
|
3417 /** Starts an register write operation. |
|
3418 * |
|
3419 * \return Zero on success, otherwise a negative error code. |
|
3420 */ |
|
3421 static ATTRIBUTES int ec_ioctl_reg_request_write( |
|
3422 ec_master_t *master, /**< EtherCAT master. */ |
|
3423 void *arg, /**< ioctl() argument. */ |
|
3424 ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ |
|
3425 ) |
|
3426 { |
|
3427 ec_ioctl_reg_request_t io; |
|
3428 ec_slave_config_t *sc; |
|
3429 ec_reg_request_t *reg; |
|
3430 |
|
3431 if (unlikely(!ctx->requested)) { |
|
3432 return -EPERM; |
|
3433 } |
|
3434 |
|
3435 if (copy_from_user(&io, (void __user *) arg, sizeof(io))) { |
|
3436 return -EFAULT; |
|
3437 } |
|
3438 |
|
3439 /* no locking of master_sem needed, because neither sc nor reg will not be |
|
3440 * deleted in the meantime. */ |
|
3441 |
|
3442 if (!(sc = ec_master_get_config(master, io.config_index))) { |
|
3443 return -ENOENT; |
|
3444 } |
|
3445 |
|
3446 if (!(reg = ec_slave_config_find_reg_request(sc, io.request_index))) { |
|
3447 return -ENOENT; |
|
3448 } |
|
3449 |
|
3450 if (io.transfer_size > reg->mem_size) { |
|
3451 return -EOVERFLOW; |
|
3452 } |
|
3453 |
|
3454 if (copy_from_user(reg->data, (void __user *) io.data, |
|
3455 io.transfer_size)) { |
|
3456 return -EFAULT; |
|
3457 } |
|
3458 |
|
3459 ecrt_reg_request_write(reg, io.address, io.transfer_size); |
|
3460 return 0; |
|
3461 } |
|
3462 |
|
3463 /*****************************************************************************/ |
|
3464 |
|
3465 /** Starts an register read operation. |
|
3466 * |
|
3467 * \return Zero on success, otherwise a negative error code. |
|
3468 */ |
|
3469 static ATTRIBUTES int ec_ioctl_reg_request_read( |
|
3470 ec_master_t *master, /**< EtherCAT master. */ |
|
3471 void *arg, /**< ioctl() argument. */ |
|
3472 ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ |
|
3473 ) |
|
3474 { |
|
3475 ec_ioctl_reg_request_t io; |
|
3476 ec_slave_config_t *sc; |
|
3477 ec_reg_request_t *reg; |
|
3478 |
|
3479 if (unlikely(!ctx->requested)) { |
|
3480 return -EPERM; |
|
3481 } |
|
3482 |
|
3483 if (copy_from_user(&io, (void __user *) arg, sizeof(io))) { |
|
3484 return -EFAULT; |
|
3485 } |
|
3486 |
|
3487 /* no locking of master_sem needed, because neither sc nor reg will not be |
|
3488 * deleted in the meantime. */ |
|
3489 |
|
3490 if (!(sc = ec_master_get_config(master, io.config_index))) { |
|
3491 return -ENOENT; |
|
3492 } |
|
3493 |
|
3494 if (!(reg = ec_slave_config_find_reg_request(sc, io.request_index))) { |
|
3495 return -ENOENT; |
|
3496 } |
|
3497 |
|
3498 if (io.transfer_size > reg->mem_size) { |
|
3499 return -EOVERFLOW; |
|
3500 } |
|
3501 |
|
3502 ecrt_reg_request_read(reg, io.address, io.transfer_size); |
|
3503 return 0; |
|
3504 } |
|
3505 |
|
3506 /*****************************************************************************/ |
|
3507 |
|
3508 /** Sets the VoE send header. |
|
3509 * |
|
3510 * \return Zero on success, otherwise a negative error code. |
|
3511 */ |
|
3512 static ATTRIBUTES int ec_ioctl_voe_send_header( |
|
3513 ec_master_t *master, /**< EtherCAT master. */ |
|
3514 void *arg, /**< ioctl() argument. */ |
|
3515 ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ |
|
3516 ) |
|
3517 { |
|
3518 ec_ioctl_voe_t data; |
|
3519 ec_slave_config_t *sc; |
|
3520 ec_voe_handler_t *voe; |
|
3521 uint32_t vendor_id; |
|
3522 uint16_t vendor_type; |
|
3523 |
|
3524 if (unlikely(!ctx->requested)) |
|
3525 return -EPERM; |
|
3526 |
|
3527 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) |
|
3528 return -EFAULT; |
|
3529 |
|
3530 if (get_user(vendor_id, data.vendor_id)) |
|
3531 return -EFAULT; |
|
3532 |
|
3533 if (get_user(vendor_type, data.vendor_type)) |
|
3534 return -EFAULT; |
|
3535 |
|
3536 /* no locking of master_sem needed, because neither sc nor voe will not be |
|
3537 * deleted in the meantime. */ |
|
3538 |
|
3539 if (!(sc = ec_master_get_config(master, data.config_index))) { |
|
3540 return -ENOENT; |
|
3541 } |
|
3542 |
|
3543 if (!(voe = ec_slave_config_find_voe_handler(sc, data.voe_index))) { |
|
3544 return -ENOENT; |
|
3545 } |
|
3546 |
|
3547 ecrt_voe_handler_send_header(voe, vendor_id, vendor_type); |
|
3548 return 0; |
|
3549 } |
|
3550 |
|
3551 /*****************************************************************************/ |
|
3552 |
|
3553 /** Gets the received VoE header. |
|
3554 * |
|
3555 * \return Zero on success, otherwise a negative error code. |
|
3556 */ |
|
3557 static ATTRIBUTES int ec_ioctl_voe_rec_header( |
|
3558 ec_master_t *master, /**< EtherCAT master. */ |
|
3559 void *arg, /**< ioctl() argument. */ |
|
3560 ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ |
|
3561 ) |
|
3562 { |
|
3563 ec_ioctl_voe_t data; |
|
3564 ec_slave_config_t *sc; |
|
3565 ec_voe_handler_t *voe; |
|
3566 uint32_t vendor_id; |
|
3567 uint16_t vendor_type; |
|
3568 |
|
3569 if (unlikely(!ctx->requested)) |
|
3570 return -EPERM; |
|
3571 |
|
3572 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) |
|
3573 return -EFAULT; |
|
3574 |
|
3575 /* no locking of master_sem needed, because neither sc nor voe will not be |
|
3576 * deleted in the meantime. */ |
|
3577 |
|
3578 if (!(sc = ec_master_get_config(master, data.config_index))) { |
|
3579 return -ENOENT; |
|
3580 } |
|
3581 |
|
3582 if (!(voe = ec_slave_config_find_voe_handler(sc, data.voe_index))) { |
|
3583 return -ENOENT; |
|
3584 } |
|
3585 |
|
3586 ecrt_voe_handler_received_header(voe, &vendor_id, &vendor_type); |
|
3587 |
|
3588 if (likely(data.vendor_id)) |
|
3589 if (put_user(vendor_id, data.vendor_id)) |
|
3590 return -EFAULT; |
|
3591 |
|
3592 if (likely(data.vendor_type)) |
|
3593 if (put_user(vendor_type, data.vendor_type)) |
|
3594 return -EFAULT; |
|
3595 |
|
3596 return 0; |
|
3597 } |
|
3598 |
|
3599 /*****************************************************************************/ |
|
3600 |
|
3601 /** Starts a VoE read operation. |
|
3602 * |
|
3603 * \return Zero on success, otherwise a negative error code. |
|
3604 */ |
|
3605 static ATTRIBUTES int ec_ioctl_voe_read( |
|
3606 ec_master_t *master, /**< EtherCAT master. */ |
|
3607 void *arg, /**< ioctl() argument. */ |
|
3608 ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ |
|
3609 ) |
|
3610 { |
|
3611 ec_ioctl_voe_t data; |
|
3612 ec_slave_config_t *sc; |
|
3613 ec_voe_handler_t *voe; |
|
3614 |
|
3615 if (unlikely(!ctx->requested)) |
|
3616 return -EPERM; |
|
3617 |
|
3618 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) |
|
3619 return -EFAULT; |
|
3620 |
|
3621 /* no locking of master_sem needed, because neither sc nor voe will not be |
|
3622 * deleted in the meantime. */ |
|
3623 |
|
3624 if (!(sc = ec_master_get_config(master, data.config_index))) { |
|
3625 return -ENOENT; |
|
3626 } |
|
3627 |
|
3628 if (!(voe = ec_slave_config_find_voe_handler(sc, data.voe_index))) { |
|
3629 return -ENOENT; |
|
3630 } |
|
3631 |
|
3632 ecrt_voe_handler_read(voe); |
|
3633 return 0; |
|
3634 } |
|
3635 |
|
3636 /*****************************************************************************/ |
|
3637 |
|
3638 /** Starts a VoE read operation without sending a sync message first. |
|
3639 * |
|
3640 * \return Zero on success, otherwise a negative error code. |
|
3641 */ |
|
3642 static ATTRIBUTES int ec_ioctl_voe_read_nosync( |
|
3643 ec_master_t *master, /**< EtherCAT master. */ |
|
3644 void *arg, /**< ioctl() argument. */ |
|
3645 ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ |
|
3646 ) |
|
3647 { |
|
3648 ec_ioctl_voe_t data; |
|
3649 ec_slave_config_t *sc; |
|
3650 ec_voe_handler_t *voe; |
|
3651 |
|
3652 if (unlikely(!ctx->requested)) |
|
3653 return -EPERM; |
|
3654 |
|
3655 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) |
|
3656 return -EFAULT; |
|
3657 |
|
3658 /* no locking of master_sem needed, because neither sc nor voe will not be |
|
3659 * deleted in the meantime. */ |
|
3660 |
|
3661 if (!(sc = ec_master_get_config(master, data.config_index))) { |
|
3662 return -ENOENT; |
|
3663 } |
|
3664 |
|
3665 if (!(voe = ec_slave_config_find_voe_handler(sc, data.voe_index))) { |
|
3666 return -ENOENT; |
|
3667 } |
|
3668 |
|
3669 ecrt_voe_handler_read_nosync(voe); |
|
3670 return 0; |
|
3671 } |
|
3672 |
|
3673 /*****************************************************************************/ |
|
3674 |
|
3675 /** Starts a VoE write operation. |
|
3676 * |
|
3677 * \return Zero on success, otherwise a negative error code. |
|
3678 */ |
|
3679 static ATTRIBUTES int ec_ioctl_voe_write( |
|
3680 ec_master_t *master, /**< EtherCAT master. */ |
|
3681 void *arg, /**< ioctl() argument. */ |
|
3682 ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ |
|
3683 ) |
|
3684 { |
|
3685 ec_ioctl_voe_t data; |
|
3686 ec_slave_config_t *sc; |
|
3687 ec_voe_handler_t *voe; |
|
3688 |
|
3689 if (unlikely(!ctx->requested)) |
|
3690 return -EPERM; |
|
3691 |
|
3692 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) |
|
3693 return -EFAULT; |
|
3694 |
|
3695 /* no locking of master_sem needed, because neither sc nor voe will not be |
|
3696 * deleted in the meantime. */ |
|
3697 |
|
3698 if (!(sc = ec_master_get_config(master, data.config_index))) { |
|
3699 return -ENOENT; |
|
3700 } |
|
3701 |
|
3702 if (!(voe = ec_slave_config_find_voe_handler(sc, data.voe_index))) { |
|
3703 return -ENOENT; |
|
3704 } |
|
3705 |
|
3706 if (data.size) { |
|
3707 if (data.size > ec_voe_handler_mem_size(voe)) |
|
3708 return -EOVERFLOW; |
|
3709 |
|
3710 if (copy_from_user(ecrt_voe_handler_data(voe), |
|
3711 (void __user *) data.data, data.size)) |
|
3712 return -EFAULT; |
|
3713 } |
|
3714 |
|
3715 ecrt_voe_handler_write(voe, data.size); |
|
3716 return 0; |
|
3717 } |
|
3718 |
|
3719 /*****************************************************************************/ |
|
3720 |
|
3721 /** Executes the VoE state machine. |
|
3722 * |
|
3723 * \return Zero on success, otherwise a negative error code. |
|
3724 */ |
|
3725 static ATTRIBUTES int ec_ioctl_voe_exec( |
|
3726 ec_master_t *master, /**< EtherCAT master. */ |
|
3727 void *arg, /**< ioctl() argument. */ |
|
3728 ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ |
|
3729 ) |
|
3730 { |
|
3731 ec_ioctl_voe_t data; |
|
3732 ec_slave_config_t *sc; |
|
3733 ec_voe_handler_t *voe; |
|
3734 |
|
3735 if (unlikely(!ctx->requested)) |
|
3736 return -EPERM; |
|
3737 |
|
3738 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) |
|
3739 return -EFAULT; |
|
3740 |
|
3741 /* no locking of master_sem needed, because neither sc nor voe will not be |
|
3742 * deleted in the meantime. */ |
|
3743 |
|
3744 if (!(sc = ec_master_get_config(master, data.config_index))) { |
|
3745 return -ENOENT; |
|
3746 } |
|
3747 |
|
3748 if (!(voe = ec_slave_config_find_voe_handler(sc, data.voe_index))) { |
|
3749 return -ENOENT; |
|
3750 } |
|
3751 |
|
3752 data.state = ecrt_voe_handler_execute(voe); |
|
3753 if (data.state == EC_REQUEST_SUCCESS && voe->dir == EC_DIR_INPUT) |
|
3754 data.size = ecrt_voe_handler_data_size(voe); |
|
3755 else |
|
3756 data.size = 0; |
|
3757 |
|
3758 if (copy_to_user((void __user *) arg, &data, sizeof(data))) |
|
3759 return -EFAULT; |
|
3760 |
|
3761 return 0; |
|
3762 } |
|
3763 |
|
3764 /*****************************************************************************/ |
|
3765 |
|
3766 /** Reads the received VoE data. |
|
3767 * |
|
3768 * \return Zero on success, otherwise a negative error code. |
|
3769 */ |
|
3770 static ATTRIBUTES int ec_ioctl_voe_data( |
|
3771 ec_master_t *master, /**< EtherCAT master. */ |
|
3772 void *arg, /**< ioctl() argument. */ |
|
3773 ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ |
|
3774 ) |
|
3775 { |
|
3776 ec_ioctl_voe_t data; |
|
3777 ec_slave_config_t *sc; |
|
3778 ec_voe_handler_t *voe; |
|
3779 |
|
3780 if (unlikely(!ctx->requested)) |
|
3781 return -EPERM; |
|
3782 |
|
3783 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) |
|
3784 return -EFAULT; |
|
3785 |
|
3786 /* no locking of master_sem needed, because neither sc nor voe will not be |
|
3787 * deleted in the meantime. */ |
|
3788 |
|
3789 if (!(sc = ec_master_get_config(master, data.config_index))) { |
|
3790 return -ENOENT; |
|
3791 } |
|
3792 |
|
3793 if (!(voe = ec_slave_config_find_voe_handler(sc, data.voe_index))) { |
|
3794 return -ENOENT; |
|
3795 } |
|
3796 |
|
3797 if (copy_to_user((void __user *) data.data, ecrt_voe_handler_data(voe), |
|
3798 ecrt_voe_handler_data_size(voe))) |
|
3799 return -EFAULT; |
|
3800 |
|
3801 return 0; |
|
3802 } |
|
3803 |
|
3804 /*****************************************************************************/ |
|
3805 |
|
3806 /** Read a file from a slave via FoE. |
|
3807 * |
|
3808 * \return Zero on success, otherwise a negative error code. |
|
3809 */ |
|
3810 static ATTRIBUTES int ec_ioctl_slave_foe_read( |
|
3811 ec_master_t *master, /**< EtherCAT master. */ |
|
3812 void *arg /**< ioctl() argument. */ |
|
3813 ) |
|
3814 { |
|
3815 ec_ioctl_slave_foe_t io; |
|
3816 ec_foe_request_t request; |
|
3817 ec_slave_t *slave; |
|
3818 int ret; |
|
3819 |
|
3820 if (copy_from_user(&io, (void __user *) arg, sizeof(io))) { |
|
3821 return -EFAULT; |
|
3822 } |
|
3823 |
|
3824 ec_foe_request_init(&request, io.file_name); |
|
3825 ret = ec_foe_request_alloc(&request, 10000); // FIXME |
|
3826 if (ret) { |
|
3827 ec_foe_request_clear(&request); |
|
3828 return ret; |
|
3829 } |
|
3830 |
|
3831 ec_foe_request_read(&request); |
|
3832 |
|
3833 if (down_interruptible(&master->master_sem)) { |
|
3834 ec_foe_request_clear(&request); |
|
3835 return -EINTR; |
|
3836 } |
|
3837 |
|
3838 if (!(slave = ec_master_find_slave(master, 0, io.slave_position))) { |
|
3839 up(&master->master_sem); |
|
3840 ec_foe_request_clear(&request); |
|
3841 EC_MASTER_ERR(master, "Slave %u does not exist!\n", |
|
3842 io.slave_position); |
|
3843 return -EINVAL; |
|
3844 } |
|
3845 |
|
3846 EC_SLAVE_DBG(slave, 1, "Scheduling FoE read request.\n"); |
|
3847 |
|
3848 // schedule request. |
|
3849 list_add_tail(&request.list, &slave->foe_requests); |
|
3850 |
|
3851 up(&master->master_sem); |
|
3852 |
|
3853 // wait for processing through FSM |
|
3854 if (wait_event_interruptible(master->request_queue, |
|
3855 request.state != EC_INT_REQUEST_QUEUED)) { |
|
3856 // interrupted by signal |
|
3857 down(&master->master_sem); |
|
3858 if (request.state == EC_INT_REQUEST_QUEUED) { |
|
3859 list_del(&request.list); |
|
3860 up(&master->master_sem); |
|
3861 ec_foe_request_clear(&request); |
|
3862 return -EINTR; |
|
3863 } |
|
3864 // request already processing: interrupt not possible. |
|
3865 up(&master->master_sem); |
|
3866 } |
|
3867 |
|
3868 // wait until master FSM has finished processing |
|
3869 wait_event(master->request_queue, request.state != EC_INT_REQUEST_BUSY); |
|
3870 |
|
3871 io.result = request.result; |
|
3872 io.error_code = request.error_code; |
|
3873 |
|
3874 if (request.state != EC_INT_REQUEST_SUCCESS) { |
|
3875 io.data_size = 0; |
|
3876 ret = -EIO; |
|
3877 } else { |
|
3878 if (request.data_size > io.buffer_size) { |
|
3879 EC_MASTER_ERR(master, "Buffer too small.\n"); |
|
3880 ec_foe_request_clear(&request); |
|
3881 return -EOVERFLOW; |
|
3882 } |
|
3883 io.data_size = request.data_size; |
|
3884 if (copy_to_user((void __user *) io.buffer, |
|
3885 request.buffer, io.data_size)) { |
|
3886 ec_foe_request_clear(&request); |
|
3887 return -EFAULT; |
|
3888 } |
|
3889 ret = 0; |
|
3890 } |
|
3891 |
|
3892 if (__copy_to_user((void __user *) arg, &io, sizeof(io))) { |
|
3893 ret = -EFAULT; |
|
3894 } |
|
3895 |
|
3896 ec_foe_request_clear(&request); |
|
3897 return ret; |
|
3898 } |
|
3899 |
|
3900 /*****************************************************************************/ |
|
3901 |
|
3902 /** Write a file to a slave via FoE |
|
3903 * |
|
3904 * \return Zero on success, otherwise a negative error code. |
|
3905 */ |
|
3906 static ATTRIBUTES int ec_ioctl_slave_foe_write( |
|
3907 ec_master_t *master, /**< EtherCAT master. */ |
|
3908 void *arg /**< ioctl() argument. */ |
|
3909 ) |
|
3910 { |
|
3911 ec_ioctl_slave_foe_t io; |
|
3912 ec_foe_request_t request; |
|
3913 ec_slave_t *slave; |
|
3914 int ret; |
|
3915 |
|
3916 if (copy_from_user(&io, (void __user *) arg, sizeof(io))) { |
|
3917 return -EFAULT; |
|
3918 } |
|
3919 |
|
3920 ec_foe_request_init(&request, io.file_name); |
|
3921 |
|
3922 ret = ec_foe_request_alloc(&request, io.buffer_size); |
|
3923 if (ret) { |
|
3924 ec_foe_request_clear(&request); |
|
3925 return ret; |
|
3926 } |
|
3927 |
|
3928 if (copy_from_user(request.buffer, |
|
3929 (void __user *) io.buffer, io.buffer_size)) { |
|
3930 ec_foe_request_clear(&request); |
|
3931 return -EFAULT; |
|
3932 } |
|
3933 |
|
3934 request.data_size = io.buffer_size; |
|
3935 ec_foe_request_write(&request); |
|
3936 |
|
3937 if (down_interruptible(&master->master_sem)) { |
|
3938 ec_foe_request_clear(&request); |
|
3939 return -EINTR; |
|
3940 } |
|
3941 |
|
3942 if (!(slave = ec_master_find_slave(master, 0, io.slave_position))) { |
|
3943 up(&master->master_sem); |
|
3944 EC_MASTER_ERR(master, "Slave %u does not exist!\n", |
|
3945 io.slave_position); |
|
3946 ec_foe_request_clear(&request); |
|
3947 return -EINVAL; |
|
3948 } |
|
3949 |
|
3950 EC_SLAVE_DBG(slave, 1, "Scheduling FoE write request.\n"); |
|
3951 |
|
3952 // schedule FoE write request. |
|
3953 list_add_tail(&request.list, &slave->foe_requests); |
|
3954 |
|
3955 up(&master->master_sem); |
|
3956 |
|
3957 // wait for processing through FSM |
|
3958 if (wait_event_interruptible(master->request_queue, |
|
3959 request.state != EC_INT_REQUEST_QUEUED)) { |
|
3960 // interrupted by signal |
|
3961 down(&master->master_sem); |
|
3962 if (request.state == EC_INT_REQUEST_QUEUED) { |
|
3963 // abort request |
|
3964 list_del(&request.list); |
|
3965 up(&master->master_sem); |
|
3966 ec_foe_request_clear(&request); |
|
3967 return -EINTR; |
|
3968 } |
|
3969 up(&master->master_sem); |
|
3970 } |
|
3971 |
|
3972 // wait until master FSM has finished processing |
|
3973 wait_event(master->request_queue, request.state != EC_INT_REQUEST_BUSY); |
|
3974 |
|
3975 io.result = request.result; |
|
3976 io.error_code = request.error_code; |
|
3977 |
|
3978 ret = request.state == EC_INT_REQUEST_SUCCESS ? 0 : -EIO; |
|
3979 |
|
3980 if (__copy_to_user((void __user *) arg, &io, sizeof(io))) { |
|
3981 ret = -EFAULT; |
|
3982 } |
|
3983 |
|
3984 ec_foe_request_clear(&request); |
|
3985 return ret; |
|
3986 } |
|
3987 |
|
3988 /*****************************************************************************/ |
|
3989 |
|
3990 /** Read an SoE IDN. |
|
3991 * |
|
3992 * \return Zero on success, otherwise a negative error code. |
|
3993 */ |
|
3994 static ATTRIBUTES int ec_ioctl_slave_soe_read( |
|
3995 ec_master_t *master, /**< EtherCAT master. */ |
|
3996 void *arg /**< ioctl() argument. */ |
|
3997 ) |
|
3998 { |
|
3999 ec_ioctl_slave_soe_read_t ioctl; |
|
4000 u8 *data; |
|
4001 int retval; |
|
4002 |
|
4003 if (copy_from_user(&ioctl, (void __user *) arg, sizeof(ioctl))) { |
|
4004 return -EFAULT; |
|
4005 } |
|
4006 |
|
4007 data = kmalloc(ioctl.mem_size, GFP_KERNEL); |
|
4008 if (!data) { |
|
4009 EC_MASTER_ERR(master, "Failed to allocate %zu bytes of IDN data.\n", |
|
4010 ioctl.mem_size); |
|
4011 return -ENOMEM; |
|
4012 } |
|
4013 |
|
4014 retval = ecrt_master_read_idn(master, ioctl.slave_position, |
|
4015 ioctl.drive_no, ioctl.idn, data, ioctl.mem_size, &ioctl.data_size, |
|
4016 &ioctl.error_code); |
|
4017 if (retval) { |
|
4018 kfree(data); |
|
4019 return retval; |
|
4020 } |
|
4021 |
|
4022 if (copy_to_user((void __user *) ioctl.data, |
|
4023 data, ioctl.data_size)) { |
|
4024 kfree(data); |
|
4025 return -EFAULT; |
|
4026 } |
|
4027 kfree(data); |
|
4028 |
|
4029 if (__copy_to_user((void __user *) arg, &ioctl, sizeof(ioctl))) { |
|
4030 retval = -EFAULT; |
|
4031 } |
|
4032 |
|
4033 EC_MASTER_DBG(master, 1, "Finished SoE read request.\n"); |
|
4034 return retval; |
|
4035 } |
|
4036 |
|
4037 /*****************************************************************************/ |
|
4038 |
|
4039 /** Write an IDN to a slave via SoE. |
|
4040 * |
|
4041 * \return Zero on success, otherwise a negative error code. |
|
4042 */ |
|
4043 static ATTRIBUTES int ec_ioctl_slave_soe_write( |
|
4044 ec_master_t *master, /**< EtherCAT master. */ |
|
4045 void *arg /**< ioctl() argument. */ |
|
4046 ) |
|
4047 { |
|
4048 ec_ioctl_slave_soe_write_t ioctl; |
|
4049 u8 *data; |
|
4050 int retval; |
|
4051 |
|
4052 if (copy_from_user(&ioctl, (void __user *) arg, sizeof(ioctl))) { |
|
4053 return -EFAULT; |
|
4054 } |
|
4055 |
|
4056 data = kmalloc(ioctl.data_size, GFP_KERNEL); |
|
4057 if (!data) { |
|
4058 EC_MASTER_ERR(master, "Failed to allocate %zu bytes of IDN data.\n", |
|
4059 ioctl.data_size); |
|
4060 return -ENOMEM; |
|
4061 } |
|
4062 if (copy_from_user(data, (void __user *) ioctl.data, ioctl.data_size)) { |
|
4063 kfree(data); |
|
4064 return -EFAULT; |
|
4065 } |
|
4066 |
|
4067 retval = ecrt_master_write_idn(master, ioctl.slave_position, |
|
4068 ioctl.drive_no, ioctl.idn, data, ioctl.data_size, |
|
4069 &ioctl.error_code); |
|
4070 kfree(data); |
|
4071 if (retval) { |
|
4072 return retval; |
|
4073 } |
|
4074 |
|
4075 if (__copy_to_user((void __user *) arg, &ioctl, sizeof(ioctl))) { |
|
4076 retval = -EFAULT; |
|
4077 } |
|
4078 |
|
4079 EC_MASTER_DBG(master, 1, "Finished SoE write request.\n"); |
|
4080 return retval; |
|
4081 } |
|
4082 |
|
4083 /*****************************************************************************/ |
|
4084 |
|
4085 /** ioctl() function to use. |
|
4086 */ |
|
4087 #ifdef EC_IOCTL_RTDM |
|
4088 #define EC_IOCTL ec_ioctl_rtdm |
|
4089 #else |
|
4090 #define EC_IOCTL ec_ioctl |
|
4091 #endif |
|
4092 |
|
4093 /** Called when an ioctl() command is issued. |
|
4094 * |
|
4095 * \return ioctl() return code. |
|
4096 */ |
|
4097 long EC_IOCTL( |
|
4098 ec_master_t *master, /**< EtherCAT master. */ |
|
4099 ec_ioctl_context_t *ctx, /**< Device context. */ |
|
4100 unsigned int cmd, /**< ioctl() command identifier. */ |
|
4101 void *arg /**< ioctl() argument. */ |
|
4102 ) |
|
4103 { |
|
4104 #if DEBUG_LATENCY |
|
4105 cycles_t a = get_cycles(), b; |
|
4106 unsigned int t; |
|
4107 #endif |
|
4108 int ret; |
|
4109 |
|
4110 switch (cmd) { |
|
4111 case EC_IOCTL_MODULE: |
|
4112 ret = ec_ioctl_module(arg); |
|
4113 break; |
|
4114 case EC_IOCTL_MASTER: |
|
4115 ret = ec_ioctl_master(master, arg); |
|
4116 break; |
|
4117 case EC_IOCTL_SLAVE: |
|
4118 ret = ec_ioctl_slave(master, arg); |
|
4119 break; |
|
4120 case EC_IOCTL_SLAVE_SYNC: |
|
4121 ret = ec_ioctl_slave_sync(master, arg); |
|
4122 break; |
|
4123 case EC_IOCTL_SLAVE_SYNC_PDO: |
|
4124 ret = ec_ioctl_slave_sync_pdo(master, arg); |
|
4125 break; |
|
4126 case EC_IOCTL_SLAVE_SYNC_PDO_ENTRY: |
|
4127 ret = ec_ioctl_slave_sync_pdo_entry(master, arg); |
|
4128 break; |
|
4129 case EC_IOCTL_DOMAIN: |
|
4130 ret = ec_ioctl_domain(master, arg); |
|
4131 break; |
|
4132 case EC_IOCTL_DOMAIN_FMMU: |
|
4133 ret = ec_ioctl_domain_fmmu(master, arg); |
|
4134 break; |
|
4135 case EC_IOCTL_DOMAIN_DATA: |
|
4136 ret = ec_ioctl_domain_data(master, arg); |
|
4137 break; |
|
4138 case EC_IOCTL_MASTER_DEBUG: |
|
4139 if (!ctx->writable) { |
|
4140 ret = -EPERM; |
|
4141 break; |
|
4142 } |
|
4143 ret = ec_ioctl_master_debug(master, arg); |
|
4144 break; |
|
4145 case EC_IOCTL_MASTER_RESCAN: |
|
4146 if (!ctx->writable) { |
|
4147 ret = -EPERM; |
|
4148 break; |
|
4149 } |
|
4150 ret = ec_ioctl_master_rescan(master, arg); |
|
4151 break; |
|
4152 case EC_IOCTL_SLAVE_STATE: |
|
4153 if (!ctx->writable) { |
|
4154 ret = -EPERM; |
|
4155 break; |
|
4156 } |
|
4157 ret = ec_ioctl_slave_state(master, arg); |
|
4158 break; |
|
4159 case EC_IOCTL_SLAVE_SDO: |
|
4160 ret = ec_ioctl_slave_sdo(master, arg); |
|
4161 break; |
|
4162 case EC_IOCTL_SLAVE_SDO_ENTRY: |
|
4163 ret = ec_ioctl_slave_sdo_entry(master, arg); |
|
4164 break; |
|
4165 case EC_IOCTL_SLAVE_SDO_UPLOAD: |
|
4166 ret = ec_ioctl_slave_sdo_upload(master, arg); |
|
4167 break; |
|
4168 case EC_IOCTL_SLAVE_SDO_DOWNLOAD: |
|
4169 if (!ctx->writable) { |
|
4170 ret = -EPERM; |
|
4171 break; |
|
4172 } |
|
4173 ret = ec_ioctl_slave_sdo_download(master, arg); |
|
4174 break; |
|
4175 case EC_IOCTL_SLAVE_SII_READ: |
|
4176 ret = ec_ioctl_slave_sii_read(master, arg); |
|
4177 break; |
|
4178 case EC_IOCTL_SLAVE_SII_WRITE: |
|
4179 if (!ctx->writable) { |
|
4180 ret = -EPERM; |
|
4181 break; |
|
4182 } |
|
4183 ret = ec_ioctl_slave_sii_write(master, arg); |
|
4184 break; |
|
4185 case EC_IOCTL_SLAVE_REG_READ: |
|
4186 ret = ec_ioctl_slave_reg_read(master, arg); |
|
4187 break; |
|
4188 case EC_IOCTL_SLAVE_REG_WRITE: |
|
4189 if (!ctx->writable) { |
|
4190 ret = -EPERM; |
|
4191 break; |
|
4192 } |
|
4193 ret = ec_ioctl_slave_reg_write(master, arg); |
|
4194 break; |
|
4195 case EC_IOCTL_SLAVE_FOE_READ: |
|
4196 ret = ec_ioctl_slave_foe_read(master, arg); |
|
4197 break; |
|
4198 case EC_IOCTL_SLAVE_FOE_WRITE: |
|
4199 if (!ctx->writable) { |
|
4200 ret = -EPERM; |
|
4201 break; |
|
4202 } |
|
4203 ret = ec_ioctl_slave_foe_write(master, arg); |
|
4204 break; |
|
4205 case EC_IOCTL_SLAVE_SOE_READ: |
|
4206 ret = ec_ioctl_slave_soe_read(master, arg); |
|
4207 break; |
|
4208 case EC_IOCTL_SLAVE_SOE_WRITE: |
|
4209 if (!ctx->writable) { |
|
4210 ret = -EPERM; |
|
4211 break; |
|
4212 } |
|
4213 ret = ec_ioctl_slave_soe_write(master, arg); |
|
4214 break; |
|
4215 case EC_IOCTL_CONFIG: |
|
4216 ret = ec_ioctl_config(master, arg); |
|
4217 break; |
|
4218 case EC_IOCTL_CONFIG_PDO: |
|
4219 ret = ec_ioctl_config_pdo(master, arg); |
|
4220 break; |
|
4221 case EC_IOCTL_CONFIG_PDO_ENTRY: |
|
4222 ret = ec_ioctl_config_pdo_entry(master, arg); |
|
4223 break; |
|
4224 case EC_IOCTL_CONFIG_SDO: |
|
4225 ret = ec_ioctl_config_sdo(master, arg); |
|
4226 break; |
|
4227 case EC_IOCTL_CONFIG_IDN: |
|
4228 ret = ec_ioctl_config_idn(master, arg); |
|
4229 break; |
|
4230 #ifdef EC_EOE |
|
4231 case EC_IOCTL_EOE_HANDLER: |
|
4232 ret = ec_ioctl_eoe_handler(master, arg); |
|
4233 break; |
|
4234 #endif |
|
4235 case EC_IOCTL_REQUEST: |
|
4236 if (!ctx->writable) { |
|
4237 ret = -EPERM; |
|
4238 break; |
|
4239 } |
|
4240 ret = ec_ioctl_request(master, arg, ctx); |
|
4241 break; |
|
4242 case EC_IOCTL_CREATE_DOMAIN: |
|
4243 if (!ctx->writable) { |
|
4244 ret = -EPERM; |
|
4245 break; |
|
4246 } |
|
4247 ret = ec_ioctl_create_domain(master, arg, ctx); |
|
4248 break; |
|
4249 case EC_IOCTL_CREATE_SLAVE_CONFIG: |
|
4250 if (!ctx->writable) { |
|
4251 ret = -EPERM; |
|
4252 break; |
|
4253 } |
|
4254 ret = ec_ioctl_create_slave_config(master, arg, ctx); |
|
4255 break; |
|
4256 case EC_IOCTL_SELECT_REF_CLOCK: |
|
4257 if (!ctx->writable) { |
|
4258 ret = -EPERM; |
|
4259 break; |
|
4260 } |
|
4261 ret = ec_ioctl_select_ref_clock(master, arg, ctx); |
|
4262 break; |
|
4263 case EC_IOCTL_ACTIVATE: |
|
4264 if (!ctx->writable) { |
|
4265 ret = -EPERM; |
|
4266 break; |
|
4267 } |
|
4268 ret = ec_ioctl_activate(master, arg, ctx); |
|
4269 break; |
|
4270 case EC_IOCTL_DEACTIVATE: |
|
4271 if (!ctx->writable) { |
|
4272 ret = -EPERM; |
|
4273 break; |
|
4274 } |
|
4275 ret = ec_ioctl_deactivate(master, arg, ctx); |
|
4276 break; |
|
4277 case EC_IOCTL_SEND: |
|
4278 if (!ctx->writable) { |
|
4279 ret = -EPERM; |
|
4280 break; |
|
4281 } |
|
4282 ret = ec_ioctl_send(master, arg, ctx); |
|
4283 break; |
|
4284 case EC_IOCTL_RECEIVE: |
|
4285 if (!ctx->writable) { |
|
4286 ret = -EPERM; |
|
4287 break; |
|
4288 } |
|
4289 ret = ec_ioctl_receive(master, arg, ctx); |
|
4290 break; |
|
4291 case EC_IOCTL_MASTER_STATE: |
|
4292 ret = ec_ioctl_master_state(master, arg, ctx); |
|
4293 break; |
|
4294 case EC_IOCTL_MASTER_LINK_STATE: |
|
4295 ret = ec_ioctl_master_link_state(master, arg, ctx); |
|
4296 break; |
|
4297 case EC_IOCTL_APP_TIME: |
|
4298 if (!ctx->writable) { |
|
4299 ret = -EPERM; |
|
4300 break; |
|
4301 } |
|
4302 ret = ec_ioctl_app_time(master, arg, ctx); |
|
4303 break; |
|
4304 case EC_IOCTL_SYNC_REF: |
|
4305 if (!ctx->writable) { |
|
4306 ret = -EPERM; |
|
4307 break; |
|
4308 } |
|
4309 ret = ec_ioctl_sync_ref(master, arg, ctx); |
|
4310 break; |
|
4311 case EC_IOCTL_SYNC_SLAVES: |
|
4312 if (!ctx->writable) { |
|
4313 ret = -EPERM; |
|
4314 break; |
|
4315 } |
|
4316 ret = ec_ioctl_sync_slaves(master, arg, ctx); |
|
4317 break; |
|
4318 case EC_IOCTL_REF_CLOCK_TIME: |
|
4319 if (!ctx->writable) { |
|
4320 ret = -EPERM; |
|
4321 break; |
|
4322 } |
|
4323 ret = ec_ioctl_ref_clock_time(master, arg, ctx); |
|
4324 break; |
|
4325 case EC_IOCTL_SYNC_MON_QUEUE: |
|
4326 if (!ctx->writable) { |
|
4327 ret = -EPERM; |
|
4328 break; |
|
4329 } |
|
4330 ret = ec_ioctl_sync_mon_queue(master, arg, ctx); |
|
4331 break; |
|
4332 case EC_IOCTL_SYNC_MON_PROCESS: |
|
4333 if (!ctx->writable) { |
|
4334 ret = -EPERM; |
|
4335 break; |
|
4336 } |
|
4337 ret = ec_ioctl_sync_mon_process(master, arg, ctx); |
|
4338 break; |
|
4339 case EC_IOCTL_RESET: |
|
4340 if (!ctx->writable) { |
|
4341 ret = -EPERM; |
|
4342 break; |
|
4343 } |
|
4344 ret = ec_ioctl_reset(master, arg, ctx); |
|
4345 break; |
|
4346 case EC_IOCTL_SC_SYNC: |
|
4347 if (!ctx->writable) { |
|
4348 ret = -EPERM; |
|
4349 break; |
|
4350 } |
|
4351 ret = ec_ioctl_sc_sync(master, arg, ctx); |
|
4352 break; |
|
4353 case EC_IOCTL_SC_WATCHDOG: |
|
4354 if (!ctx->writable) { |
|
4355 ret = -EPERM; |
|
4356 break; |
|
4357 } |
|
4358 ret = ec_ioctl_sc_watchdog(master, arg, ctx); |
|
4359 break; |
|
4360 case EC_IOCTL_SC_ADD_PDO: |
|
4361 if (!ctx->writable) { |
|
4362 ret = -EPERM; |
|
4363 break; |
|
4364 } |
|
4365 ret = ec_ioctl_sc_add_pdo(master, arg, ctx); |
|
4366 break; |
|
4367 case EC_IOCTL_SC_CLEAR_PDOS: |
|
4368 if (!ctx->writable) { |
|
4369 ret = -EPERM; |
|
4370 break; |
|
4371 } |
|
4372 ret = ec_ioctl_sc_clear_pdos(master, arg, ctx); |
|
4373 break; |
|
4374 case EC_IOCTL_SC_ADD_ENTRY: |
|
4375 if (!ctx->writable) { |
|
4376 ret = -EPERM; |
|
4377 break; |
|
4378 } |
|
4379 ret = ec_ioctl_sc_add_entry(master, arg, ctx); |
|
4380 break; |
|
4381 case EC_IOCTL_SC_CLEAR_ENTRIES: |
|
4382 if (!ctx->writable) { |
|
4383 ret = -EPERM; |
|
4384 break; |
|
4385 } |
|
4386 ret = ec_ioctl_sc_clear_entries(master, arg, ctx); |
|
4387 break; |
|
4388 case EC_IOCTL_SC_REG_PDO_ENTRY: |
|
4389 if (!ctx->writable) { |
|
4390 ret = -EPERM; |
|
4391 break; |
|
4392 } |
|
4393 ret = ec_ioctl_sc_reg_pdo_entry(master, arg, ctx); |
|
4394 break; |
|
4395 case EC_IOCTL_SC_REG_PDO_POS: |
|
4396 if (!ctx->writable) { |
|
4397 ret = -EPERM; |
|
4398 break; |
|
4399 } |
|
4400 ret = ec_ioctl_sc_reg_pdo_pos(master, arg, ctx); |
|
4401 break; |
|
4402 case EC_IOCTL_SC_DC: |
|
4403 if (!ctx->writable) { |
|
4404 ret = -EPERM; |
|
4405 break; |
|
4406 } |
|
4407 ret = ec_ioctl_sc_dc(master, arg, ctx); |
|
4408 break; |
|
4409 case EC_IOCTL_SC_SDO: |
|
4410 if (!ctx->writable) { |
|
4411 ret = -EPERM; |
|
4412 break; |
|
4413 } |
|
4414 ret = ec_ioctl_sc_sdo(master, arg, ctx); |
|
4415 break; |
|
4416 case EC_IOCTL_SC_EMERG_SIZE: |
|
4417 if (!ctx->writable) { |
|
4418 ret = -EPERM; |
|
4419 break; |
|
4420 } |
|
4421 ret = ec_ioctl_sc_emerg_size(master, arg, ctx); |
|
4422 break; |
|
4423 case EC_IOCTL_SC_EMERG_POP: |
|
4424 if (!ctx->writable) { |
|
4425 ret = -EPERM; |
|
4426 break; |
|
4427 } |
|
4428 ret = ec_ioctl_sc_emerg_pop(master, arg, ctx); |
|
4429 break; |
|
4430 case EC_IOCTL_SC_EMERG_CLEAR: |
|
4431 if (!ctx->writable) { |
|
4432 ret = -EPERM; |
|
4433 break; |
|
4434 } |
|
4435 ret = ec_ioctl_sc_emerg_clear(master, arg, ctx); |
|
4436 break; |
|
4437 case EC_IOCTL_SC_EMERG_OVERRUNS: |
|
4438 ret = ec_ioctl_sc_emerg_overruns(master, arg, ctx); |
|
4439 break; |
|
4440 case EC_IOCTL_SC_SDO_REQUEST: |
|
4441 if (!ctx->writable) { |
|
4442 ret = -EPERM; |
|
4443 break; |
|
4444 } |
|
4445 ret = ec_ioctl_sc_create_sdo_request(master, arg, ctx); |
|
4446 break; |
|
4447 case EC_IOCTL_SC_REG_REQUEST: |
|
4448 if (!ctx->writable) { |
|
4449 ret = -EPERM; |
|
4450 break; |
|
4451 } |
|
4452 ret = ec_ioctl_sc_create_reg_request(master, arg, ctx); |
|
4453 break; |
|
4454 case EC_IOCTL_SC_VOE: |
|
4455 if (!ctx->writable) { |
|
4456 ret = -EPERM; |
|
4457 break; |
|
4458 } |
|
4459 ret = ec_ioctl_sc_create_voe_handler(master, arg, ctx); |
|
4460 break; |
|
4461 case EC_IOCTL_SC_STATE: |
|
4462 ret = ec_ioctl_sc_state(master, arg, ctx); |
|
4463 break; |
|
4464 case EC_IOCTL_SC_IDN: |
|
4465 if (!ctx->writable) { |
|
4466 ret = -EPERM; |
|
4467 break; |
|
4468 } |
|
4469 ret = ec_ioctl_sc_idn(master, arg, ctx); |
|
4470 break; |
|
4471 case EC_IOCTL_DOMAIN_SIZE: |
|
4472 ret = ec_ioctl_domain_size(master, arg, ctx); |
|
4473 break; |
|
4474 case EC_IOCTL_DOMAIN_OFFSET: |
|
4475 ret = ec_ioctl_domain_offset(master, arg, ctx); |
|
4476 break; |
|
4477 case EC_IOCTL_DOMAIN_PROCESS: |
|
4478 if (!ctx->writable) { |
|
4479 ret = -EPERM; |
|
4480 break; |
|
4481 } |
|
4482 ret = ec_ioctl_domain_process(master, arg, ctx); |
|
4483 break; |
|
4484 case EC_IOCTL_DOMAIN_QUEUE: |
|
4485 if (!ctx->writable) { |
|
4486 ret = -EPERM; |
|
4487 break; |
|
4488 } |
|
4489 ret = ec_ioctl_domain_queue(master, arg, ctx); |
|
4490 break; |
|
4491 case EC_IOCTL_DOMAIN_STATE: |
|
4492 ret = ec_ioctl_domain_state(master, arg, ctx); |
|
4493 break; |
|
4494 case EC_IOCTL_SDO_REQUEST_INDEX: |
|
4495 if (!ctx->writable) { |
|
4496 ret = -EPERM; |
|
4497 break; |
|
4498 } |
|
4499 ret = ec_ioctl_sdo_request_index(master, arg, ctx); |
|
4500 break; |
|
4501 case EC_IOCTL_SDO_REQUEST_TIMEOUT: |
|
4502 if (!ctx->writable) { |
|
4503 ret = -EPERM; |
|
4504 break; |
|
4505 } |
|
4506 ret = ec_ioctl_sdo_request_timeout(master, arg, ctx); |
|
4507 break; |
|
4508 case EC_IOCTL_SDO_REQUEST_STATE: |
|
4509 ret = ec_ioctl_sdo_request_state(master, arg, ctx); |
|
4510 break; |
|
4511 case EC_IOCTL_SDO_REQUEST_READ: |
|
4512 if (!ctx->writable) { |
|
4513 ret = -EPERM; |
|
4514 break; |
|
4515 } |
|
4516 ret = ec_ioctl_sdo_request_read(master, arg, ctx); |
|
4517 break; |
|
4518 case EC_IOCTL_SDO_REQUEST_WRITE: |
|
4519 if (!ctx->writable) { |
|
4520 ret = -EPERM; |
|
4521 break; |
|
4522 } |
|
4523 ret = ec_ioctl_sdo_request_write(master, arg, ctx); |
|
4524 break; |
|
4525 case EC_IOCTL_SDO_REQUEST_DATA: |
|
4526 ret = ec_ioctl_sdo_request_data(master, arg, ctx); |
|
4527 break; |
|
4528 case EC_IOCTL_REG_REQUEST_DATA: |
|
4529 ret = ec_ioctl_reg_request_data(master, arg, ctx); |
|
4530 break; |
|
4531 case EC_IOCTL_REG_REQUEST_STATE: |
|
4532 ret = ec_ioctl_reg_request_state(master, arg, ctx); |
|
4533 break; |
|
4534 case EC_IOCTL_REG_REQUEST_WRITE: |
|
4535 if (!ctx->writable) { |
|
4536 ret = -EPERM; |
|
4537 break; |
|
4538 } |
|
4539 ret = ec_ioctl_reg_request_write(master, arg, ctx); |
|
4540 break; |
|
4541 case EC_IOCTL_REG_REQUEST_READ: |
|
4542 if (!ctx->writable) { |
|
4543 ret = -EPERM; |
|
4544 break; |
|
4545 } |
|
4546 ret = ec_ioctl_reg_request_read(master, arg, ctx); |
|
4547 break; |
|
4548 case EC_IOCTL_VOE_SEND_HEADER: |
|
4549 if (!ctx->writable) { |
|
4550 ret = -EPERM; |
|
4551 break; |
|
4552 } |
|
4553 ret = ec_ioctl_voe_send_header(master, arg, ctx); |
|
4554 break; |
|
4555 case EC_IOCTL_VOE_REC_HEADER: |
|
4556 ret = ec_ioctl_voe_rec_header(master, arg, ctx); |
|
4557 break; |
|
4558 case EC_IOCTL_VOE_READ: |
|
4559 if (!ctx->writable) { |
|
4560 ret = -EPERM; |
|
4561 break; |
|
4562 } |
|
4563 ret = ec_ioctl_voe_read(master, arg, ctx); |
|
4564 break; |
|
4565 case EC_IOCTL_VOE_READ_NOSYNC: |
|
4566 if (!ctx->writable) { |
|
4567 ret = -EPERM; |
|
4568 break; |
|
4569 } |
|
4570 ret = ec_ioctl_voe_read_nosync(master, arg, ctx); |
|
4571 break; |
|
4572 case EC_IOCTL_VOE_WRITE: |
|
4573 if (!ctx->writable) { |
|
4574 ret = -EPERM; |
|
4575 break; |
|
4576 } |
|
4577 ret = ec_ioctl_voe_write(master, arg, ctx); |
|
4578 break; |
|
4579 case EC_IOCTL_VOE_EXEC: |
|
4580 if (!ctx->writable) { |
|
4581 ret = -EPERM; |
|
4582 break; |
|
4583 } |
|
4584 ret = ec_ioctl_voe_exec(master, arg, ctx); |
|
4585 break; |
|
4586 case EC_IOCTL_VOE_DATA: |
|
4587 ret = ec_ioctl_voe_data(master, arg, ctx); |
|
4588 break; |
|
4589 case EC_IOCTL_SET_SEND_INTERVAL: |
|
4590 if (!ctx->writable) { |
|
4591 ret = -EPERM; |
|
4592 break; |
|
4593 } |
|
4594 ret = ec_ioctl_set_send_interval(master, arg, ctx); |
|
4595 break; |
|
4596 default: |
|
4597 ret = -ENOTTY; |
|
4598 break; |
|
4599 } |
|
4600 |
|
4601 #if DEBUG_LATENCY |
|
4602 b = get_cycles(); |
|
4603 t = (unsigned int) ((b - a) * 1000LL) / cpu_khz; |
|
4604 if (t > 50) { |
|
4605 EC_MASTER_WARN(master, "ioctl(0x%02x) took %u us.\n", |
|
4606 _IOC_NR(cmd), t); |
|
4607 } |
|
4608 #endif |
|
4609 |
|
4610 return ret; |
|
4611 } |
|
4612 |
|
4613 /*****************************************************************************/ |