97 void ec_cdev_clear(ec_cdev_t *cdev /**< EtherCAT XML device */) |
97 void ec_cdev_clear(ec_cdev_t *cdev /**< EtherCAT XML device */) |
98 { |
98 { |
99 cdev_del(&cdev->cdev); |
99 cdev_del(&cdev->cdev); |
100 } |
100 } |
101 |
101 |
|
102 /*****************************************************************************/ |
|
103 |
|
104 /** Get master information. |
|
105 */ |
|
106 int ec_cdev_ioctl_master( |
|
107 ec_master_t *master, /**< EtherCAT master. */ |
|
108 unsigned long arg /**< Userspace address to store the results. */ |
|
109 ) |
|
110 { |
|
111 ec_ioctl_master_t data; |
|
112 |
|
113 down(&master->master_sem); |
|
114 data.slave_count = master->slave_count; |
|
115 data.config_count = ec_master_config_count(master); |
|
116 data.domain_count = ec_master_domain_count(master); |
|
117 data.phase = (uint8_t) master->phase; |
|
118 up(&master->master_sem); |
|
119 |
|
120 down(&master->device_sem); |
|
121 memcpy(data.devices[0].address, master->main_mac, ETH_ALEN); |
|
122 data.devices[0].attached = master->main_device.dev ? 1 : 0; |
|
123 data.devices[0].tx_count = master->main_device.tx_count; |
|
124 data.devices[0].rx_count = master->main_device.rx_count; |
|
125 memcpy(data.devices[1].address, master->backup_mac, ETH_ALEN); |
|
126 data.devices[1].attached = master->backup_device.dev ? 1 : 0; |
|
127 data.devices[1].tx_count = master->backup_device.tx_count; |
|
128 data.devices[1].rx_count = master->backup_device.rx_count; |
|
129 up(&master->device_sem); |
|
130 |
|
131 if (copy_to_user((void __user *) arg, &data, sizeof(data))) |
|
132 return -EFAULT; |
|
133 |
|
134 return 0; |
|
135 } |
|
136 |
|
137 /*****************************************************************************/ |
|
138 |
|
139 /** Get slave information. |
|
140 */ |
|
141 int ec_cdev_ioctl_slave( |
|
142 ec_master_t *master, /**< EtherCAT master. */ |
|
143 unsigned long arg /**< Userspace address to store the results. */ |
|
144 ) |
|
145 { |
|
146 ec_ioctl_slave_t data; |
|
147 const ec_slave_t *slave; |
|
148 |
|
149 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { |
|
150 return -EFAULT; |
|
151 } |
|
152 |
|
153 down(&master->master_sem); |
|
154 |
|
155 if (!(slave = ec_master_find_slave_const( |
|
156 master, 0, data.position))) { |
|
157 up(&master->master_sem); |
|
158 EC_ERR("Slave %u does not exist!\n", data.position); |
|
159 return -EINVAL; |
|
160 } |
|
161 |
|
162 data.vendor_id = slave->sii.vendor_id; |
|
163 data.product_code = slave->sii.product_code; |
|
164 data.revision_number = slave->sii.revision_number; |
|
165 data.serial_number = slave->sii.serial_number; |
|
166 data.alias = slave->sii.alias; |
|
167 data.rx_mailbox_offset = slave->sii.rx_mailbox_offset; |
|
168 data.rx_mailbox_size = slave->sii.rx_mailbox_size; |
|
169 data.tx_mailbox_offset = slave->sii.tx_mailbox_offset; |
|
170 data.tx_mailbox_size = slave->sii.tx_mailbox_size; |
|
171 data.mailbox_protocols = slave->sii.mailbox_protocols; |
|
172 data.has_general_category = slave->sii.has_general; |
|
173 data.coe_details = slave->sii.coe_details; |
|
174 data.general_flags = slave->sii.general_flags; |
|
175 data.current_on_ebus = slave->sii.current_on_ebus; |
|
176 data.state = slave->current_state; |
|
177 data.error_flag = slave->error_flag; |
|
178 |
|
179 data.sync_count = slave->sii.sync_count; |
|
180 data.sdo_count = ec_slave_sdo_count(slave); |
|
181 data.sii_nwords = slave->sii_nwords; |
|
182 |
|
183 if (slave->sii.name) { |
|
184 strncpy(data.name, slave->sii.name, |
|
185 EC_IOCTL_STRING_SIZE); |
|
186 data.name[EC_IOCTL_STRING_SIZE - 1] = 0; |
|
187 } else { |
|
188 data.name[0] = 0; |
|
189 } |
|
190 |
|
191 up(&master->master_sem); |
|
192 |
|
193 if (copy_to_user((void __user *) arg, &data, sizeof(data))) |
|
194 return -EFAULT; |
|
195 |
|
196 return 0; |
|
197 } |
|
198 |
|
199 /*****************************************************************************/ |
|
200 |
|
201 /** Get slave sync manager information. |
|
202 */ |
|
203 int ec_cdev_ioctl_slave_sync( |
|
204 ec_master_t *master, /**< EtherCAT master. */ |
|
205 unsigned long arg /**< Userspace address to store the results. */ |
|
206 ) |
|
207 { |
|
208 ec_ioctl_slave_sync_t data; |
|
209 const ec_slave_t *slave; |
|
210 const ec_sync_t *sync; |
|
211 |
|
212 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { |
|
213 return -EFAULT; |
|
214 } |
|
215 |
|
216 down(&master->master_sem); |
|
217 |
|
218 if (!(slave = ec_master_find_slave_const( |
|
219 master, 0, data.slave_position))) { |
|
220 up(&master->master_sem); |
|
221 EC_ERR("Slave %u does not exist!\n", data.slave_position); |
|
222 return -EINVAL; |
|
223 } |
|
224 |
|
225 if (data.sync_index >= slave->sii.sync_count) { |
|
226 up(&master->master_sem); |
|
227 EC_ERR("Sync manager %u does not exist in slave %u!\n", |
|
228 data.sync_index, data.slave_position); |
|
229 return -EINVAL; |
|
230 } |
|
231 |
|
232 sync = &slave->sii.syncs[data.sync_index]; |
|
233 |
|
234 data.physical_start_address = sync->physical_start_address; |
|
235 data.default_size = sync->default_length; |
|
236 data.control_register = sync->control_register; |
|
237 data.enable = sync->enable; |
|
238 data.assign_source = sync->assign_source; |
|
239 data.pdo_count = ec_pdo_list_count(&sync->pdos); |
|
240 |
|
241 up(&master->master_sem); |
|
242 |
|
243 if (copy_to_user((void __user *) arg, &data, sizeof(data))) |
|
244 return -EFAULT; |
|
245 |
|
246 return 0; |
|
247 } |
|
248 |
|
249 /*****************************************************************************/ |
|
250 |
|
251 /** Get slave sync manager Pdo information. |
|
252 */ |
|
253 int ec_cdev_ioctl_slave_sync_pdo( |
|
254 ec_master_t *master, /**< EtherCAT master. */ |
|
255 unsigned long arg /**< Userspace address to store the results. */ |
|
256 ) |
|
257 { |
|
258 ec_ioctl_slave_sync_pdo_t data; |
|
259 const ec_slave_t *slave; |
|
260 const ec_sync_t *sync; |
|
261 const ec_pdo_t *pdo; |
|
262 |
|
263 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { |
|
264 return -EFAULT; |
|
265 } |
|
266 |
|
267 down(&master->master_sem); |
|
268 |
|
269 if (!(slave = ec_master_find_slave_const( |
|
270 master, 0, data.slave_position))) { |
|
271 up(&master->master_sem); |
|
272 EC_ERR("Slave %u does not exist!\n", data.slave_position); |
|
273 return -EINVAL; |
|
274 } |
|
275 |
|
276 if (data.sync_index >= slave->sii.sync_count) { |
|
277 up(&master->master_sem); |
|
278 EC_ERR("Sync manager %u does not exist in slave %u!\n", |
|
279 data.sync_index, data.slave_position); |
|
280 return -EINVAL; |
|
281 } |
|
282 |
|
283 sync = &slave->sii.syncs[data.sync_index]; |
|
284 if (!(pdo = ec_pdo_list_find_pdo_by_pos_const( |
|
285 &sync->pdos, data.pdo_pos))) { |
|
286 up(&master->master_sem); |
|
287 EC_ERR("Sync manager %u does not contain a Pdo with " |
|
288 "position %u in slave %u!\n", data.sync_index, |
|
289 data.pdo_pos, data.slave_position); |
|
290 return -EINVAL; |
|
291 } |
|
292 |
|
293 data.index = pdo->index; |
|
294 data.entry_count = ec_pdo_entry_count(pdo); |
|
295 |
|
296 if (pdo->name) { |
|
297 strncpy(data.name, pdo->name, EC_IOCTL_STRING_SIZE); |
|
298 data.name[EC_IOCTL_STRING_SIZE - 1] = 0; |
|
299 } else { |
|
300 data.name[0] = 0; |
|
301 } |
|
302 |
|
303 up(&master->master_sem); |
|
304 |
|
305 if (copy_to_user((void __user *) arg, &data, sizeof(data))) |
|
306 return -EFAULT; |
|
307 |
|
308 return 0; |
|
309 } |
|
310 |
|
311 /*****************************************************************************/ |
|
312 |
|
313 /** Get slave sync manager Pdo entry information. |
|
314 */ |
|
315 int ec_cdev_ioctl_slave_sync_pdo_entry( |
|
316 ec_master_t *master, /**< EtherCAT master. */ |
|
317 unsigned long arg /**< Userspace address to store the results. */ |
|
318 ) |
|
319 { |
|
320 ec_ioctl_slave_sync_pdo_entry_t data; |
|
321 const ec_slave_t *slave; |
|
322 const ec_sync_t *sync; |
|
323 const ec_pdo_t *pdo; |
|
324 const ec_pdo_entry_t *entry; |
|
325 |
|
326 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { |
|
327 return -EFAULT; |
|
328 } |
|
329 |
|
330 down(&master->master_sem); |
|
331 |
|
332 if (!(slave = ec_master_find_slave_const( |
|
333 master, 0, data.slave_position))) { |
|
334 up(&master->master_sem); |
|
335 EC_ERR("Slave %u does not exist!\n", data.slave_position); |
|
336 return -EINVAL; |
|
337 } |
|
338 |
|
339 if (data.sync_index >= slave->sii.sync_count) { |
|
340 up(&master->master_sem); |
|
341 EC_ERR("Sync manager %u does not exist in slave %u!\n", |
|
342 data.sync_index, data.slave_position); |
|
343 return -EINVAL; |
|
344 } |
|
345 |
|
346 sync = &slave->sii.syncs[data.sync_index]; |
|
347 if (!(pdo = ec_pdo_list_find_pdo_by_pos_const( |
|
348 &sync->pdos, data.pdo_pos))) { |
|
349 up(&master->master_sem); |
|
350 EC_ERR("Sync manager %u does not contain a Pdo with " |
|
351 "position %u in slave %u!\n", data.sync_index, |
|
352 data.pdo_pos, data.slave_position); |
|
353 return -EINVAL; |
|
354 } |
|
355 |
|
356 if (!(entry = ec_pdo_find_entry_by_pos_const( |
|
357 pdo, data.entry_pos))) { |
|
358 up(&master->master_sem); |
|
359 EC_ERR("Pdo 0x%04X does not contain an entry with " |
|
360 "position %u in slave %u!\n", data.pdo_pos, |
|
361 data.entry_pos, data.slave_position); |
|
362 return -EINVAL; |
|
363 } |
|
364 |
|
365 data.index = entry->index; |
|
366 data.subindex = entry->subindex; |
|
367 data.bit_length = entry->bit_length; |
|
368 if (entry->name) { |
|
369 strncpy(data.name, entry->name, EC_IOCTL_STRING_SIZE); |
|
370 data.name[EC_IOCTL_STRING_SIZE - 1] = 0; |
|
371 } else { |
|
372 data.name[0] = 0; |
|
373 } |
|
374 |
|
375 up(&master->master_sem); |
|
376 |
|
377 if (copy_to_user((void __user *) arg, &data, sizeof(data))) |
|
378 return -EFAULT; |
|
379 |
|
380 return 0; |
|
381 } |
|
382 |
|
383 /*****************************************************************************/ |
|
384 |
|
385 /** Get domain information. |
|
386 */ |
|
387 int ec_cdev_ioctl_domain( |
|
388 ec_master_t *master, /**< EtherCAT master. */ |
|
389 unsigned long arg /**< Userspace address to store the results. */ |
|
390 ) |
|
391 { |
|
392 ec_ioctl_domain_t data; |
|
393 const ec_domain_t *domain; |
|
394 |
|
395 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { |
|
396 return -EFAULT; |
|
397 } |
|
398 |
|
399 down(&master->master_sem); |
|
400 |
|
401 if (!(domain = ec_master_find_domain_const(master, data.index))) { |
|
402 up(&master->master_sem); |
|
403 EC_ERR("Domain %u does not exist!\n", data.index); |
|
404 return -EINVAL; |
|
405 } |
|
406 |
|
407 data.data_size = domain->data_size; |
|
408 data.logical_base_address = domain->logical_base_address; |
|
409 data.working_counter = domain->working_counter; |
|
410 data.expected_working_counter = domain->expected_working_counter; |
|
411 data.fmmu_count = ec_domain_fmmu_count(domain); |
|
412 |
|
413 up(&master->master_sem); |
|
414 |
|
415 if (copy_to_user((void __user *) arg, &data, sizeof(data))) |
|
416 return -EFAULT; |
|
417 |
|
418 return 0; |
|
419 } |
|
420 |
|
421 /*****************************************************************************/ |
|
422 |
|
423 /** Get domain FMMU information. |
|
424 */ |
|
425 int ec_cdev_ioctl_domain_fmmu( |
|
426 ec_master_t *master, /**< EtherCAT master. */ |
|
427 unsigned long arg /**< Userspace address to store the results. */ |
|
428 ) |
|
429 { |
|
430 ec_ioctl_domain_fmmu_t data; |
|
431 const ec_domain_t *domain; |
|
432 const ec_fmmu_config_t *fmmu; |
|
433 |
|
434 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { |
|
435 return -EFAULT; |
|
436 } |
|
437 |
|
438 down(&master->master_sem); |
|
439 |
|
440 if (!(domain = ec_master_find_domain_const(master, data.domain_index))) { |
|
441 up(&master->master_sem); |
|
442 EC_ERR("Domain %u does not exist!\n", data.domain_index); |
|
443 return -EINVAL; |
|
444 } |
|
445 |
|
446 if (!(fmmu = ec_domain_find_fmmu(domain, data.fmmu_index))) { |
|
447 up(&master->master_sem); |
|
448 EC_ERR("Domain %u has less than %u fmmu configurations.\n", |
|
449 data.domain_index, data.fmmu_index + 1); |
|
450 return -EINVAL; |
|
451 } |
|
452 |
|
453 data.slave_config_alias = fmmu->sc->alias; |
|
454 data.slave_config_position = fmmu->sc->position; |
|
455 data.sync_index = fmmu->sync_index; |
|
456 data.dir = fmmu->dir; |
|
457 data.logical_address = fmmu->logical_start_address; |
|
458 data.data_size = fmmu->data_size; |
|
459 |
|
460 up(&master->master_sem); |
|
461 |
|
462 if (copy_to_user((void __user *) arg, &data, sizeof(data))) |
|
463 return -EFAULT; |
|
464 |
|
465 return 0; |
|
466 } |
|
467 |
|
468 /*****************************************************************************/ |
|
469 |
|
470 /** Get domain data. |
|
471 */ |
|
472 int ec_cdev_ioctl_domain_data( |
|
473 ec_master_t *master, /**< EtherCAT master. */ |
|
474 unsigned long arg /**< Userspace address to store the results. */ |
|
475 ) |
|
476 { |
|
477 ec_ioctl_domain_data_t data; |
|
478 const ec_domain_t *domain; |
|
479 |
|
480 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { |
|
481 return -EFAULT; |
|
482 } |
|
483 |
|
484 down(&master->master_sem); |
|
485 |
|
486 if (!(domain = ec_master_find_domain_const(master, data.domain_index))) { |
|
487 up(&master->master_sem); |
|
488 EC_ERR("Domain %u does not exist!\n", data.domain_index); |
|
489 return -EINVAL; |
|
490 } |
|
491 |
|
492 if (domain->data_size != data.data_size) { |
|
493 up(&master->master_sem); |
|
494 EC_ERR("Data size mismatch %u/%u!\n", |
|
495 data.data_size, domain->data_size); |
|
496 return -EFAULT; |
|
497 } |
|
498 |
|
499 if (copy_to_user((void __user *) data.target, domain->data, |
|
500 domain->data_size)) |
|
501 return -EFAULT; |
|
502 |
|
503 up(&master->master_sem); |
|
504 return 0; |
|
505 } |
|
506 |
|
507 /*****************************************************************************/ |
|
508 |
|
509 /** Set master debug level. |
|
510 */ |
|
511 int ec_cdev_ioctl_master_debug( |
|
512 ec_master_t *master, /**< EtherCAT master. */ |
|
513 unsigned long arg /**< ioctl() argument. */ |
|
514 ) |
|
515 { |
|
516 if (ec_master_debug_level(master, (unsigned int) arg)) |
|
517 return -EINVAL; |
|
518 |
|
519 return 0; |
|
520 } |
|
521 |
|
522 /*****************************************************************************/ |
|
523 |
|
524 /** Set slave state. |
|
525 */ |
|
526 int ec_cdev_ioctl_slave_state( |
|
527 ec_master_t *master, /**< EtherCAT master. */ |
|
528 unsigned long arg /**< ioctl() argument. */ |
|
529 ) |
|
530 { |
|
531 ec_ioctl_slave_state_t data; |
|
532 ec_slave_t *slave; |
|
533 |
|
534 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { |
|
535 return -EFAULT; |
|
536 } |
|
537 |
|
538 down(&master->master_sem); |
|
539 |
|
540 if (!(slave = ec_master_find_slave( |
|
541 master, 0, data.slave_position))) { |
|
542 EC_ERR("Slave %u does not exist!\n", data.slave_position); |
|
543 return -EINVAL; |
|
544 } |
|
545 |
|
546 ec_slave_request_state(slave, data.requested_state); |
|
547 |
|
548 up(&master->master_sem); |
|
549 return 0; |
|
550 } |
|
551 |
|
552 /*****************************************************************************/ |
|
553 |
|
554 /** Get slave Sdo information. |
|
555 */ |
|
556 int ec_cdev_ioctl_slave_sdo( |
|
557 ec_master_t *master, /**< EtherCAT master. */ |
|
558 unsigned long arg /**< ioctl() argument. */ |
|
559 ) |
|
560 { |
|
561 ec_ioctl_slave_sdo_t data; |
|
562 const ec_slave_t *slave; |
|
563 const ec_sdo_t *sdo; |
|
564 |
|
565 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { |
|
566 return -EFAULT; |
|
567 } |
|
568 |
|
569 down(&master->master_sem); |
|
570 |
|
571 if (!(slave = ec_master_find_slave_const( |
|
572 master, 0, data.slave_position))) { |
|
573 up(&master->master_sem); |
|
574 EC_ERR("Slave %u does not exist!\n", data.slave_position); |
|
575 return -EINVAL; |
|
576 } |
|
577 |
|
578 if (!(sdo = ec_slave_get_sdo_by_pos_const( |
|
579 slave, data.sdo_position))) { |
|
580 up(&master->master_sem); |
|
581 EC_ERR("Sdo %u does not exist in slave %u!\n", |
|
582 data.sdo_position, data.slave_position); |
|
583 return -EINVAL; |
|
584 } |
|
585 |
|
586 data.sdo_index = sdo->index; |
|
587 data.max_subindex = sdo->max_subindex; |
|
588 |
|
589 if (sdo->name) { |
|
590 strncpy(data.name, sdo->name, EC_IOCTL_STRING_SIZE); |
|
591 data.name[EC_IOCTL_STRING_SIZE - 1] = 0; |
|
592 } else { |
|
593 data.name[0] = 0; |
|
594 } |
|
595 |
|
596 up(&master->master_sem); |
|
597 |
|
598 if (copy_to_user((void __user *) arg, &data, sizeof(data))) |
|
599 return -EFAULT; |
|
600 |
|
601 return 0; |
|
602 } |
|
603 |
|
604 /*****************************************************************************/ |
|
605 |
|
606 /** Get slave Sdo entry information. |
|
607 */ |
|
608 int ec_cdev_ioctl_slave_sdo_entry( |
|
609 ec_master_t *master, /**< EtherCAT master. */ |
|
610 unsigned long arg /**< ioctl() argument. */ |
|
611 ) |
|
612 { |
|
613 ec_ioctl_slave_sdo_entry_t data; |
|
614 const ec_slave_t *slave; |
|
615 const ec_sdo_t *sdo; |
|
616 const ec_sdo_entry_t *entry; |
|
617 |
|
618 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { |
|
619 return -EFAULT; |
|
620 } |
|
621 |
|
622 down(&master->master_sem); |
|
623 |
|
624 if (!(slave = ec_master_find_slave_const( |
|
625 master, 0, data.slave_position))) { |
|
626 up(&master->master_sem); |
|
627 EC_ERR("Slave %u does not exist!\n", data.slave_position); |
|
628 return -EINVAL; |
|
629 } |
|
630 |
|
631 if (data.sdo_spec <= 0) { |
|
632 if (!(sdo = ec_slave_get_sdo_by_pos_const( |
|
633 slave, -data.sdo_spec))) { |
|
634 up(&master->master_sem); |
|
635 EC_ERR("Sdo %u does not exist in slave %u!\n", |
|
636 -data.sdo_spec, data.slave_position); |
|
637 return -EINVAL; |
|
638 } |
|
639 } else { |
|
640 if (!(sdo = ec_slave_get_sdo_const( |
|
641 slave, data.sdo_spec))) { |
|
642 up(&master->master_sem); |
|
643 EC_ERR("Sdo 0x%04X does not exist in slave %u!\n", |
|
644 data.sdo_spec, data.slave_position); |
|
645 return -EINVAL; |
|
646 } |
|
647 } |
|
648 |
|
649 if (!(entry = ec_sdo_get_entry_const( |
|
650 sdo, data.sdo_entry_subindex))) { |
|
651 up(&master->master_sem); |
|
652 EC_ERR("Sdo entry 0x%04X:%02X does not exist " |
|
653 "in slave %u!\n", sdo->index, |
|
654 data.sdo_entry_subindex, data.slave_position); |
|
655 return -EINVAL; |
|
656 } |
|
657 |
|
658 data.data_type = entry->data_type; |
|
659 data.bit_length = entry->bit_length; |
|
660 |
|
661 if (entry->description) { |
|
662 strncpy(data.description, entry->description, |
|
663 EC_IOCTL_STRING_SIZE); |
|
664 data.description[EC_IOCTL_STRING_SIZE - 1] |
|
665 = 0; |
|
666 } else { |
|
667 data.description[0] = 0; |
|
668 } |
|
669 |
|
670 up(&master->master_sem); |
|
671 |
|
672 if (copy_to_user((void __user *) arg, &data, sizeof(data))) |
|
673 return -EFAULT; |
|
674 |
|
675 return 0; |
|
676 } |
|
677 |
|
678 /*****************************************************************************/ |
|
679 |
|
680 /** Upload Sdo. |
|
681 */ |
|
682 int ec_cdev_ioctl_slave_sdo_upload( |
|
683 ec_master_t *master, /**< EtherCAT master. */ |
|
684 unsigned long arg /**< ioctl() argument. */ |
|
685 ) |
|
686 { |
|
687 ec_ioctl_slave_sdo_upload_t data; |
|
688 ec_master_sdo_request_t request; |
|
689 int retval; |
|
690 |
|
691 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { |
|
692 return -EFAULT; |
|
693 } |
|
694 |
|
695 ec_sdo_request_init(&request.req); |
|
696 ec_sdo_request_address(&request.req, |
|
697 data.sdo_index, data.sdo_entry_subindex); |
|
698 ecrt_sdo_request_read(&request.req); |
|
699 |
|
700 down(&master->master_sem); |
|
701 |
|
702 if (!(request.slave = ec_master_find_slave( |
|
703 master, 0, data.slave_position))) { |
|
704 up(&master->master_sem); |
|
705 ec_sdo_request_clear(&request.req); |
|
706 EC_ERR("Slave %u does not exist!\n", data.slave_position); |
|
707 return -EINVAL; |
|
708 } |
|
709 |
|
710 // schedule request. |
|
711 list_add_tail(&request.list, &master->slave_sdo_requests); |
|
712 |
|
713 up(&master->master_sem); |
|
714 |
|
715 // wait for processing through FSM |
|
716 if (wait_event_interruptible(master->sdo_queue, |
|
717 request.req.state != EC_REQUEST_QUEUED)) { |
|
718 // interrupted by signal |
|
719 down(&master->master_sem); |
|
720 if (request.req.state == EC_REQUEST_QUEUED) { |
|
721 list_del(&request.req.list); |
|
722 up(&master->master_sem); |
|
723 ec_sdo_request_clear(&request.req); |
|
724 return -EINTR; |
|
725 } |
|
726 // request already processing: interrupt not possible. |
|
727 up(&master->master_sem); |
|
728 } |
|
729 |
|
730 // wait until master FSM has finished processing |
|
731 wait_event(master->sdo_queue, request.req.state != EC_REQUEST_BUSY); |
|
732 |
|
733 data.abort_code = request.req.abort_code; |
|
734 |
|
735 if (request.req.state != EC_REQUEST_SUCCESS) { |
|
736 data.data_size = 0; |
|
737 retval = -EIO; |
|
738 } else { |
|
739 if (request.req.data_size > data.target_size) { |
|
740 EC_ERR("Buffer too small.\n"); |
|
741 ec_sdo_request_clear(&request.req); |
|
742 return -EOVERFLOW; |
|
743 } |
|
744 data.data_size = request.req.data_size; |
|
745 |
|
746 if (copy_to_user((void __user *) data.target, |
|
747 request.req.data, data.data_size)) { |
|
748 ec_sdo_request_clear(&request.req); |
|
749 return -EFAULT; |
|
750 } |
|
751 retval = 0; |
|
752 } |
|
753 |
|
754 if (__copy_to_user((void __user *) arg, &data, sizeof(data))) { |
|
755 retval = -EFAULT; |
|
756 } |
|
757 |
|
758 ec_sdo_request_clear(&request.req); |
|
759 return retval; |
|
760 } |
|
761 |
|
762 /*****************************************************************************/ |
|
763 |
|
764 /** Download Sdo. |
|
765 */ |
|
766 int ec_cdev_ioctl_slave_sdo_download( |
|
767 ec_master_t *master, /**< EtherCAT master. */ |
|
768 unsigned long arg /**< ioctl() argument. */ |
|
769 ) |
|
770 { |
|
771 ec_ioctl_slave_sdo_download_t data; |
|
772 ec_master_sdo_request_t request; |
|
773 int retval; |
|
774 |
|
775 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { |
|
776 return -EFAULT; |
|
777 } |
|
778 |
|
779 // copy data to download |
|
780 if (!data.data_size) { |
|
781 EC_ERR("Zero data size!\n"); |
|
782 return -EINVAL; |
|
783 } |
|
784 |
|
785 ec_sdo_request_init(&request.req); |
|
786 ec_sdo_request_address(&request.req, |
|
787 data.sdo_index, data.sdo_entry_subindex); |
|
788 if (ec_sdo_request_alloc(&request.req, data.data_size)) { |
|
789 ec_sdo_request_clear(&request.req); |
|
790 return -ENOMEM; |
|
791 } |
|
792 if (copy_from_user(request.req.data, |
|
793 (void __user *) data.data, data.data_size)) { |
|
794 ec_sdo_request_clear(&request.req); |
|
795 return -EFAULT; |
|
796 } |
|
797 request.req.data_size = data.data_size; |
|
798 ecrt_sdo_request_write(&request.req); |
|
799 |
|
800 |
|
801 down(&master->master_sem); |
|
802 |
|
803 if (!(request.slave = ec_master_find_slave( |
|
804 master, 0, data.slave_position))) { |
|
805 up(&master->master_sem); |
|
806 EC_ERR("Slave %u does not exist!\n", data.slave_position); |
|
807 ec_sdo_request_clear(&request.req); |
|
808 return -EINVAL; |
|
809 } |
|
810 |
|
811 // schedule request. |
|
812 list_add_tail(&request.list, &master->slave_sdo_requests); |
|
813 |
|
814 up(&master->master_sem); |
|
815 |
|
816 // wait for processing through FSM |
|
817 if (wait_event_interruptible(master->sdo_queue, |
|
818 request.req.state != EC_REQUEST_QUEUED)) { |
|
819 // interrupted by signal |
|
820 down(&master->master_sem); |
|
821 if (request.req.state == EC_REQUEST_QUEUED) { |
|
822 list_del(&request.req.list); |
|
823 up(&master->master_sem); |
|
824 ec_sdo_request_clear(&request.req); |
|
825 return -EINTR; |
|
826 } |
|
827 // request already processing: interrupt not possible. |
|
828 up(&master->master_sem); |
|
829 } |
|
830 |
|
831 // wait until master FSM has finished processing |
|
832 wait_event(master->sdo_queue, request.req.state != EC_REQUEST_BUSY); |
|
833 |
|
834 data.abort_code = request.req.abort_code; |
|
835 |
|
836 retval = request.req.state == EC_REQUEST_SUCCESS ? 0 : -EIO; |
|
837 |
|
838 if (__copy_to_user((void __user *) arg, &data, sizeof(data))) { |
|
839 retval = -EFAULT; |
|
840 } |
|
841 |
|
842 ec_sdo_request_clear(&request.req); |
|
843 return retval; |
|
844 } |
|
845 |
|
846 /*****************************************************************************/ |
|
847 |
|
848 /** Read a slave's SII. |
|
849 */ |
|
850 int ec_cdev_ioctl_slave_sii_read( |
|
851 ec_master_t *master, /**< EtherCAT master. */ |
|
852 unsigned long arg /**< ioctl() argument. */ |
|
853 ) |
|
854 { |
|
855 ec_ioctl_slave_sii_t data; |
|
856 const ec_slave_t *slave; |
|
857 int retval; |
|
858 |
|
859 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { |
|
860 return -EFAULT; |
|
861 } |
|
862 |
|
863 down(&master->master_sem); |
|
864 |
|
865 if (!(slave = ec_master_find_slave_const( |
|
866 master, 0, data.slave_position))) { |
|
867 up(&master->master_sem); |
|
868 EC_ERR("Slave %u does not exist!\n", data.slave_position); |
|
869 return -EINVAL; |
|
870 } |
|
871 |
|
872 if (!data.nwords |
|
873 || data.offset + data.nwords > slave->sii_nwords) { |
|
874 up(&master->master_sem); |
|
875 EC_ERR("Invalid SII read offset/size %u/%u for slave " |
|
876 "SII size %u!\n", data.offset, |
|
877 data.nwords, slave->sii_nwords); |
|
878 return -EINVAL; |
|
879 } |
|
880 |
|
881 if (copy_to_user((void __user *) data.words, |
|
882 slave->sii_words + data.offset, data.nwords * 2)) |
|
883 retval = -EFAULT; |
|
884 else |
|
885 retval = 0; |
|
886 |
|
887 up(&master->master_sem); |
|
888 return retval; |
|
889 } |
|
890 |
|
891 /*****************************************************************************/ |
|
892 |
|
893 /** Write a slave's SII. |
|
894 */ |
|
895 int ec_cdev_ioctl_slave_sii_write( |
|
896 ec_master_t *master, /**< EtherCAT master. */ |
|
897 unsigned long arg /**< ioctl() argument. */ |
|
898 ) |
|
899 { |
|
900 ec_ioctl_slave_sii_t data; |
|
901 ec_slave_t *slave; |
|
902 unsigned int byte_size; |
|
903 uint16_t *words; |
|
904 ec_sii_write_request_t request; |
|
905 |
|
906 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { |
|
907 return -EFAULT; |
|
908 } |
|
909 |
|
910 if (!data.nwords) |
|
911 return 0; |
|
912 |
|
913 byte_size = sizeof(uint16_t) * data.nwords; |
|
914 if (!(words = kmalloc(byte_size, GFP_KERNEL))) { |
|
915 EC_ERR("Failed to allocate %u bytes for SII contents.\n", |
|
916 byte_size); |
|
917 return -ENOMEM; |
|
918 } |
|
919 |
|
920 if (copy_from_user(words, |
|
921 (void __user *) data.words, byte_size)) { |
|
922 kfree(words); |
|
923 return -EFAULT; |
|
924 } |
|
925 |
|
926 down(&master->master_sem); |
|
927 |
|
928 if (!(slave = ec_master_find_slave( |
|
929 master, 0, data.slave_position))) { |
|
930 up(&master->master_sem); |
|
931 EC_ERR("Slave %u does not exist!\n", data.slave_position); |
|
932 kfree(words); |
|
933 return -EINVAL; |
|
934 } |
|
935 |
|
936 // init SII write request |
|
937 INIT_LIST_HEAD(&request.list); |
|
938 request.slave = slave; |
|
939 request.words = words; |
|
940 request.offset = data.offset; |
|
941 request.nwords = data.nwords; |
|
942 request.state = EC_REQUEST_QUEUED; |
|
943 |
|
944 // schedule SII write request. |
|
945 list_add_tail(&request.list, &master->sii_requests); |
|
946 |
|
947 up(&master->master_sem); |
|
948 |
|
949 // wait for processing through FSM |
|
950 if (wait_event_interruptible(master->sii_queue, |
|
951 request.state != EC_REQUEST_QUEUED)) { |
|
952 // interrupted by signal |
|
953 down(&master->master_sem); |
|
954 if (request.state == EC_REQUEST_QUEUED) { |
|
955 // abort request |
|
956 list_del(&request.list); |
|
957 up(&master->master_sem); |
|
958 kfree(words); |
|
959 return -EINTR; |
|
960 } |
|
961 up(&master->master_sem); |
|
962 } |
|
963 |
|
964 // wait until master FSM has finished processing |
|
965 wait_event(master->sii_queue, request.state != EC_REQUEST_BUSY); |
|
966 |
|
967 kfree(words); |
|
968 |
|
969 return request.state == EC_REQUEST_SUCCESS ? 0 : -EIO; |
|
970 } |
|
971 |
|
972 /*****************************************************************************/ |
|
973 |
|
974 /** Get slave configuration information. |
|
975 */ |
|
976 int ec_cdev_ioctl_config( |
|
977 ec_master_t *master, /**< EtherCAT master. */ |
|
978 unsigned long arg /**< ioctl() argument. */ |
|
979 ) |
|
980 { |
|
981 ec_ioctl_config_t data; |
|
982 const ec_slave_config_t *sc; |
|
983 uint8_t i; |
|
984 |
|
985 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { |
|
986 return -EFAULT; |
|
987 } |
|
988 |
|
989 down(&master->master_sem); |
|
990 |
|
991 if (!(sc = ec_master_get_config_const( |
|
992 master, data.config_index))) { |
|
993 up(&master->master_sem); |
|
994 EC_ERR("Slave config %u does not exist!\n", |
|
995 data.config_index); |
|
996 return -EINVAL; |
|
997 } |
|
998 |
|
999 data.alias = sc->alias; |
|
1000 data.position = sc->position; |
|
1001 data.vendor_id = sc->vendor_id; |
|
1002 data.product_code = sc->product_code; |
|
1003 for (i = 0; i < EC_MAX_SYNCS; i++) { |
|
1004 data.syncs[i].dir = sc->sync_configs[i].dir; |
|
1005 data.syncs[i].pdo_count = |
|
1006 ec_pdo_list_count(&sc->sync_configs[i].pdos); |
|
1007 } |
|
1008 data.sdo_count = ec_slave_config_sdo_count(sc); |
|
1009 data.attached = sc->slave != NULL; |
|
1010 data.operational = sc->slave && |
|
1011 sc->slave->current_state == EC_SLAVE_STATE_OP; |
|
1012 |
|
1013 up(&master->master_sem); |
|
1014 |
|
1015 if (copy_to_user((void __user *) arg, &data, sizeof(data))) |
|
1016 return -EFAULT; |
|
1017 |
|
1018 return 0; |
|
1019 } |
|
1020 |
|
1021 /*****************************************************************************/ |
|
1022 |
|
1023 /** Get slave configuration Pdo information. |
|
1024 */ |
|
1025 int ec_cdev_ioctl_config_pdo( |
|
1026 ec_master_t *master, /**< EtherCAT master. */ |
|
1027 unsigned long arg /**< ioctl() argument. */ |
|
1028 ) |
|
1029 { |
|
1030 ec_ioctl_config_pdo_t data; |
|
1031 const ec_slave_config_t *sc; |
|
1032 const ec_pdo_t *pdo; |
|
1033 |
|
1034 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { |
|
1035 return -EFAULT; |
|
1036 } |
|
1037 |
|
1038 if (data.sync_index >= EC_MAX_SYNCS) { |
|
1039 EC_ERR("Invalid sync manager index %u!\n", |
|
1040 data.sync_index); |
|
1041 return -EINVAL; |
|
1042 } |
|
1043 |
|
1044 down(&master->master_sem); |
|
1045 |
|
1046 if (!(sc = ec_master_get_config_const( |
|
1047 master, data.config_index))) { |
|
1048 up(&master->master_sem); |
|
1049 EC_ERR("Slave config %u does not exist!\n", |
|
1050 data.config_index); |
|
1051 return -EINVAL; |
|
1052 } |
|
1053 |
|
1054 if (!(pdo = ec_pdo_list_find_pdo_by_pos_const( |
|
1055 &sc->sync_configs[data.sync_index].pdos, |
|
1056 data.pdo_pos))) { |
|
1057 up(&master->master_sem); |
|
1058 EC_ERR("Invalid Pdo position!\n"); |
|
1059 return -EINVAL; |
|
1060 } |
|
1061 |
|
1062 data.index = pdo->index; |
|
1063 data.entry_count = ec_pdo_entry_count(pdo); |
|
1064 |
|
1065 if (pdo->name) { |
|
1066 strncpy(data.name, pdo->name, EC_IOCTL_STRING_SIZE); |
|
1067 data.name[EC_IOCTL_STRING_SIZE - 1] = 0; |
|
1068 } else { |
|
1069 data.name[0] = 0; |
|
1070 } |
|
1071 |
|
1072 up(&master->master_sem); |
|
1073 |
|
1074 if (copy_to_user((void __user *) arg, &data, sizeof(data))) |
|
1075 return -EFAULT; |
|
1076 |
|
1077 return 0; |
|
1078 } |
|
1079 |
|
1080 /*****************************************************************************/ |
|
1081 |
|
1082 /** Get slave configuration Pdo entry information. |
|
1083 */ |
|
1084 int ec_cdev_ioctl_config_pdo_entry( |
|
1085 ec_master_t *master, /**< EtherCAT master. */ |
|
1086 unsigned long arg /**< ioctl() argument. */ |
|
1087 ) |
|
1088 { |
|
1089 ec_ioctl_config_pdo_entry_t data; |
|
1090 const ec_slave_config_t *sc; |
|
1091 const ec_pdo_t *pdo; |
|
1092 const ec_pdo_entry_t *entry; |
|
1093 |
|
1094 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { |
|
1095 return -EFAULT; |
|
1096 } |
|
1097 |
|
1098 if (data.sync_index >= EC_MAX_SYNCS) { |
|
1099 EC_ERR("Invalid sync manager index %u!\n", |
|
1100 data.sync_index); |
|
1101 return -EINVAL; |
|
1102 } |
|
1103 |
|
1104 down(&master->master_sem); |
|
1105 |
|
1106 if (!(sc = ec_master_get_config_const( |
|
1107 master, data.config_index))) { |
|
1108 up(&master->master_sem); |
|
1109 EC_ERR("Slave config %u does not exist!\n", |
|
1110 data.config_index); |
|
1111 return -EINVAL; |
|
1112 } |
|
1113 |
|
1114 if (!(pdo = ec_pdo_list_find_pdo_by_pos_const( |
|
1115 &sc->sync_configs[data.sync_index].pdos, |
|
1116 data.pdo_pos))) { |
|
1117 up(&master->master_sem); |
|
1118 EC_ERR("Invalid Pdo position!\n"); |
|
1119 return -EINVAL; |
|
1120 } |
|
1121 |
|
1122 if (!(entry = ec_pdo_find_entry_by_pos_const( |
|
1123 pdo, data.entry_pos))) { |
|
1124 up(&master->master_sem); |
|
1125 EC_ERR("Entry not found!\n"); |
|
1126 return -EINVAL; |
|
1127 } |
|
1128 |
|
1129 data.index = entry->index; |
|
1130 data.subindex = entry->subindex; |
|
1131 data.bit_length = entry->bit_length; |
|
1132 if (entry->name) { |
|
1133 strncpy(data.name, entry->name, EC_IOCTL_STRING_SIZE); |
|
1134 data.name[EC_IOCTL_STRING_SIZE - 1] = 0; |
|
1135 } else { |
|
1136 data.name[0] = 0; |
|
1137 } |
|
1138 |
|
1139 up(&master->master_sem); |
|
1140 |
|
1141 if (copy_to_user((void __user *) arg, &data, sizeof(data))) |
|
1142 return -EFAULT; |
|
1143 |
|
1144 return 0; |
|
1145 } |
|
1146 |
|
1147 /*****************************************************************************/ |
|
1148 |
|
1149 /** Get slave configuration Sdo information. |
|
1150 */ |
|
1151 int ec_cdev_ioctl_config_sdo( |
|
1152 ec_master_t *master, /**< EtherCAT master. */ |
|
1153 unsigned long arg /**< ioctl() argument. */ |
|
1154 ) |
|
1155 { |
|
1156 ec_ioctl_config_sdo_t data; |
|
1157 const ec_slave_config_t *sc; |
|
1158 const ec_sdo_request_t *req; |
|
1159 |
|
1160 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { |
|
1161 return -EFAULT; |
|
1162 } |
|
1163 |
|
1164 down(&master->master_sem); |
|
1165 |
|
1166 if (!(sc = ec_master_get_config_const( |
|
1167 master, data.config_index))) { |
|
1168 up(&master->master_sem); |
|
1169 EC_ERR("Slave config %u does not exist!\n", |
|
1170 data.config_index); |
|
1171 return -EINVAL; |
|
1172 } |
|
1173 |
|
1174 if (!(req = ec_slave_config_get_sdo_by_pos_const( |
|
1175 sc, data.sdo_pos))) { |
|
1176 up(&master->master_sem); |
|
1177 EC_ERR("Invalid Sdo position!\n"); |
|
1178 return -EINVAL; |
|
1179 } |
|
1180 |
|
1181 data.index = req->index; |
|
1182 data.subindex = req->subindex; |
|
1183 data.size = req->data_size; |
|
1184 memcpy(&data.data, req->data, min((u32) data.size, (u32) 4)); |
|
1185 |
|
1186 up(&master->master_sem); |
|
1187 |
|
1188 if (copy_to_user((void __user *) arg, &data, sizeof(data))) |
|
1189 return -EFAULT; |
|
1190 |
|
1191 return 0; |
|
1192 } |
|
1193 |
102 /****************************************************************************** |
1194 /****************************************************************************** |
103 * File operations |
1195 * File operations |
104 *****************************************************************************/ |
1196 *****************************************************************************/ |
105 |
1197 |
106 int eccdev_open(struct inode *inode, struct file *filp) |
1198 int eccdev_open(struct inode *inode, struct file *filp) |
130 |
1222 |
131 long eccdev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) |
1223 long eccdev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) |
132 { |
1224 { |
133 ec_cdev_t *cdev = (ec_cdev_t *) filp->private_data; |
1225 ec_cdev_t *cdev = (ec_cdev_t *) filp->private_data; |
134 ec_master_t *master = cdev->master; |
1226 ec_master_t *master = cdev->master; |
135 long retval = 0; |
|
136 |
1227 |
137 if (master->debug_level) |
1228 if (master->debug_level) |
138 EC_DBG("ioctl(filp = %x, cmd = %u (%u), arg = %x)\n", |
1229 EC_DBG("ioctl(filp = %x, cmd = %u (%u), arg = %x)\n", |
139 (u32) filp, (u32) cmd, (u32) _IOC_NR(cmd), (u32) arg); |
1230 (u32) filp, (u32) cmd, (u32) _IOC_NR(cmd), (u32) arg); |
140 |
1231 |
141 down(&master->master_sem); |
|
142 |
|
143 switch (cmd) { |
1232 switch (cmd) { |
144 case EC_IOCTL_MASTER: |
1233 case EC_IOCTL_MASTER: |
145 { |
1234 return ec_cdev_ioctl_master(master, arg); |
146 ec_ioctl_master_t data; |
|
147 |
|
148 data.slave_count = master->slave_count; |
|
149 data.config_count = ec_master_config_count(master); |
|
150 data.domain_count = ec_master_domain_count(master); |
|
151 data.phase = (uint8_t) master->phase; |
|
152 |
|
153 memcpy(data.devices[0].address, master->main_mac, ETH_ALEN); |
|
154 data.devices[0].attached = master->main_device.dev ? 1 : 0; |
|
155 data.devices[0].tx_count = master->main_device.tx_count; |
|
156 data.devices[0].rx_count = master->main_device.rx_count; |
|
157 memcpy(data.devices[1].address, master->backup_mac, ETH_ALEN); |
|
158 data.devices[1].attached = master->backup_device.dev ? 1 : 0; |
|
159 data.devices[1].tx_count = master->backup_device.tx_count; |
|
160 data.devices[1].rx_count = master->backup_device.rx_count; |
|
161 |
|
162 if (copy_to_user((void __user *) arg, &data, sizeof(data))) |
|
163 retval = -EFAULT; |
|
164 break; |
|
165 } |
|
166 |
|
167 case EC_IOCTL_SLAVE: |
1235 case EC_IOCTL_SLAVE: |
168 { |
1236 return ec_cdev_ioctl_slave(master, arg); |
169 ec_ioctl_slave_t data; |
1237 case EC_IOCTL_SLAVE_SYNC: |
170 const ec_slave_t *slave; |
1238 return ec_cdev_ioctl_slave_sync(master, arg); |
171 |
1239 case EC_IOCTL_SLAVE_SYNC_PDO: |
172 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { |
1240 return ec_cdev_ioctl_slave_sync_pdo(master, arg); |
173 retval = -EFAULT; |
1241 case EC_IOCTL_SLAVE_SYNC_PDO_ENTRY: |
174 break; |
1242 return ec_cdev_ioctl_slave_sync_pdo_entry(master, arg); |
175 } |
|
176 |
|
177 if (!(slave = ec_master_find_slave( |
|
178 master, 0, data.position))) { |
|
179 EC_ERR("Slave %u does not exist!\n", data.position); |
|
180 retval = -EINVAL; |
|
181 break; |
|
182 } |
|
183 |
|
184 data.vendor_id = slave->sii.vendor_id; |
|
185 data.product_code = slave->sii.product_code; |
|
186 data.revision_number = slave->sii.revision_number; |
|
187 data.serial_number = slave->sii.serial_number; |
|
188 data.alias = slave->sii.alias; |
|
189 data.rx_mailbox_offset = slave->sii.rx_mailbox_offset; |
|
190 data.rx_mailbox_size = slave->sii.rx_mailbox_size; |
|
191 data.tx_mailbox_offset = slave->sii.tx_mailbox_offset; |
|
192 data.tx_mailbox_size = slave->sii.tx_mailbox_size; |
|
193 data.mailbox_protocols = slave->sii.mailbox_protocols; |
|
194 data.has_general_category = slave->sii.has_general; |
|
195 data.coe_details = slave->sii.coe_details; |
|
196 data.general_flags = slave->sii.general_flags; |
|
197 data.current_on_ebus = slave->sii.current_on_ebus; |
|
198 data.state = slave->current_state; |
|
199 data.error_flag = slave->error_flag; |
|
200 |
|
201 data.sync_count = slave->sii.sync_count; |
|
202 data.sdo_count = ec_slave_sdo_count(slave); |
|
203 data.sii_nwords = slave->sii_nwords; |
|
204 |
|
205 if (slave->sii.name) { |
|
206 strncpy(data.name, slave->sii.name, |
|
207 EC_IOCTL_STRING_SIZE); |
|
208 data.name[EC_IOCTL_STRING_SIZE - 1] = 0; |
|
209 } else { |
|
210 data.name[0] = 0; |
|
211 } |
|
212 |
|
213 if (copy_to_user((void __user *) arg, &data, sizeof(data))) |
|
214 retval = -EFAULT; |
|
215 break; |
|
216 } |
|
217 |
|
218 case EC_IOCTL_SYNC: |
|
219 { |
|
220 ec_ioctl_sync_t data; |
|
221 const ec_slave_t *slave; |
|
222 const ec_sync_t *sync; |
|
223 |
|
224 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { |
|
225 retval = -EFAULT; |
|
226 break; |
|
227 } |
|
228 |
|
229 if (!(slave = ec_master_find_slave( |
|
230 master, 0, data.slave_position))) { |
|
231 EC_ERR("Slave %u does not exist!\n", data.slave_position); |
|
232 retval = -EINVAL; |
|
233 break; |
|
234 } |
|
235 |
|
236 if (data.sync_index >= slave->sii.sync_count) { |
|
237 EC_ERR("Sync manager %u does not exist in slave %u!\n", |
|
238 data.sync_index, data.slave_position); |
|
239 retval = -EINVAL; |
|
240 break; |
|
241 } |
|
242 |
|
243 sync = &slave->sii.syncs[data.sync_index]; |
|
244 |
|
245 data.physical_start_address = sync->physical_start_address; |
|
246 data.default_size = sync->default_length; |
|
247 data.control_register = sync->control_register; |
|
248 data.enable = sync->enable; |
|
249 data.assign_source = sync->assign_source; |
|
250 data.pdo_count = ec_pdo_list_count(&sync->pdos); |
|
251 |
|
252 if (copy_to_user((void __user *) arg, &data, sizeof(data))) |
|
253 retval = -EFAULT; |
|
254 break; |
|
255 } |
|
256 |
|
257 case EC_IOCTL_PDO: |
|
258 { |
|
259 ec_ioctl_pdo_t data; |
|
260 const ec_slave_t *slave; |
|
261 const ec_sync_t *sync; |
|
262 const ec_pdo_t *pdo; |
|
263 |
|
264 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { |
|
265 retval = -EFAULT; |
|
266 break; |
|
267 } |
|
268 |
|
269 if (!(slave = ec_master_find_slave( |
|
270 master, 0, data.slave_position))) { |
|
271 EC_ERR("Slave %u does not exist!\n", data.slave_position); |
|
272 retval = -EINVAL; |
|
273 break; |
|
274 } |
|
275 |
|
276 if (data.sync_index >= slave->sii.sync_count) { |
|
277 EC_ERR("Sync manager %u does not exist in slave %u!\n", |
|
278 data.sync_index, data.slave_position); |
|
279 retval = -EINVAL; |
|
280 break; |
|
281 } |
|
282 |
|
283 sync = &slave->sii.syncs[data.sync_index]; |
|
284 if (!(pdo = ec_pdo_list_find_pdo_by_pos_const( |
|
285 &sync->pdos, data.pdo_pos))) { |
|
286 EC_ERR("Sync manager %u does not contain a Pdo with " |
|
287 "position %u in slave %u!\n", data.sync_index, |
|
288 data.pdo_pos, data.slave_position); |
|
289 retval = -EINVAL; |
|
290 break; |
|
291 } |
|
292 |
|
293 data.index = pdo->index; |
|
294 data.entry_count = ec_pdo_entry_count(pdo); |
|
295 |
|
296 if (pdo->name) { |
|
297 strncpy(data.name, pdo->name, EC_IOCTL_STRING_SIZE); |
|
298 data.name[EC_IOCTL_STRING_SIZE - 1] = 0; |
|
299 } else { |
|
300 data.name[0] = 0; |
|
301 } |
|
302 |
|
303 if (copy_to_user((void __user *) arg, &data, sizeof(data))) |
|
304 retval = -EFAULT; |
|
305 break; |
|
306 } |
|
307 |
|
308 case EC_IOCTL_PDO_ENTRY: |
|
309 { |
|
310 ec_ioctl_pdo_entry_t data; |
|
311 const ec_slave_t *slave; |
|
312 const ec_sync_t *sync; |
|
313 const ec_pdo_t *pdo; |
|
314 const ec_pdo_entry_t *entry; |
|
315 |
|
316 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { |
|
317 retval = -EFAULT; |
|
318 break; |
|
319 } |
|
320 |
|
321 if (!(slave = ec_master_find_slave( |
|
322 master, 0, data.slave_position))) { |
|
323 EC_ERR("Slave %u does not exist!\n", data.slave_position); |
|
324 retval = -EINVAL; |
|
325 break; |
|
326 } |
|
327 |
|
328 if (data.sync_index >= slave->sii.sync_count) { |
|
329 EC_ERR("Sync manager %u does not exist in slave %u!\n", |
|
330 data.sync_index, data.slave_position); |
|
331 retval = -EINVAL; |
|
332 break; |
|
333 } |
|
334 |
|
335 sync = &slave->sii.syncs[data.sync_index]; |
|
336 if (!(pdo = ec_pdo_list_find_pdo_by_pos_const( |
|
337 &sync->pdos, data.pdo_pos))) { |
|
338 EC_ERR("Sync manager %u does not contain a Pdo with " |
|
339 "position %u in slave %u!\n", data.sync_index, |
|
340 data.pdo_pos, data.slave_position); |
|
341 retval = -EINVAL; |
|
342 break; |
|
343 } |
|
344 |
|
345 if (!(entry = ec_pdo_find_entry_by_pos_const( |
|
346 pdo, data.entry_pos))) { |
|
347 EC_ERR("Pdo 0x%04X does not contain an entry with " |
|
348 "position %u in slave %u!\n", data.pdo_pos, |
|
349 data.entry_pos, data.slave_position); |
|
350 retval = -EINVAL; |
|
351 break; |
|
352 } |
|
353 |
|
354 data.index = entry->index; |
|
355 data.subindex = entry->subindex; |
|
356 data.bit_length = entry->bit_length; |
|
357 if (entry->name) { |
|
358 strncpy(data.name, entry->name, EC_IOCTL_STRING_SIZE); |
|
359 data.name[EC_IOCTL_STRING_SIZE - 1] = 0; |
|
360 } else { |
|
361 data.name[0] = 0; |
|
362 } |
|
363 |
|
364 if (copy_to_user((void __user *) arg, &data, sizeof(data))) |
|
365 retval = -EFAULT; |
|
366 break; |
|
367 } |
|
368 |
|
369 case EC_IOCTL_DOMAIN: |
1243 case EC_IOCTL_DOMAIN: |
370 { |
1244 return ec_cdev_ioctl_domain(master, arg); |
371 ec_ioctl_domain_t data; |
|
372 const ec_domain_t *domain; |
|
373 |
|
374 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { |
|
375 retval = -EFAULT; |
|
376 break; |
|
377 } |
|
378 |
|
379 if (!(domain = ec_master_find_domain(master, data.index))) { |
|
380 EC_ERR("Domain %u does not exist!\n", data.index); |
|
381 retval = -EINVAL; |
|
382 break; |
|
383 } |
|
384 |
|
385 data.data_size = domain->data_size; |
|
386 data.logical_base_address = domain->logical_base_address; |
|
387 data.working_counter = domain->working_counter; |
|
388 data.expected_working_counter = domain->expected_working_counter; |
|
389 data.fmmu_count = ec_domain_fmmu_count(domain); |
|
390 |
|
391 if (copy_to_user((void __user *) arg, &data, sizeof(data))) |
|
392 retval = -EFAULT; |
|
393 break; |
|
394 } |
|
395 |
|
396 case EC_IOCTL_DOMAIN_FMMU: |
1245 case EC_IOCTL_DOMAIN_FMMU: |
397 { |
1246 return ec_cdev_ioctl_domain_fmmu(master, arg); |
398 ec_ioctl_domain_fmmu_t data; |
1247 case EC_IOCTL_DOMAIN_DATA: |
399 const ec_domain_t *domain; |
1248 return ec_cdev_ioctl_domain_data(master, arg); |
400 const ec_fmmu_config_t *fmmu; |
1249 case EC_IOCTL_MASTER_DEBUG: |
401 |
|
402 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { |
|
403 retval = -EFAULT; |
|
404 break; |
|
405 } |
|
406 |
|
407 if (!(domain = ec_master_find_domain(master, data.domain_index))) { |
|
408 EC_ERR("Domain %u does not exist!\n", data.domain_index); |
|
409 retval = -EINVAL; |
|
410 break; |
|
411 } |
|
412 |
|
413 if (!(fmmu = ec_domain_find_fmmu(domain, data.fmmu_index))) { |
|
414 EC_ERR("Domain %u has less than %u fmmu configurations.\n", |
|
415 data.domain_index, data.fmmu_index + 1); |
|
416 retval = -EINVAL; |
|
417 break; |
|
418 } |
|
419 |
|
420 data.slave_config_alias = fmmu->sc->alias; |
|
421 data.slave_config_position = fmmu->sc->position; |
|
422 data.sync_index = fmmu->sync_index; |
|
423 data.dir = fmmu->dir; |
|
424 data.logical_address = fmmu->logical_start_address; |
|
425 data.data_size = fmmu->data_size; |
|
426 |
|
427 if (copy_to_user((void __user *) arg, &data, sizeof(data))) |
|
428 retval = -EFAULT; |
|
429 break; |
|
430 } |
|
431 |
|
432 case EC_IOCTL_DATA: |
|
433 { |
|
434 ec_ioctl_data_t data; |
|
435 const ec_domain_t *domain; |
|
436 |
|
437 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { |
|
438 retval = -EFAULT; |
|
439 break; |
|
440 } |
|
441 |
|
442 if (!(domain = ec_master_find_domain(master, data.domain_index))) { |
|
443 EC_ERR("Domain %u does not exist!\n", data.domain_index); |
|
444 retval = -EINVAL; |
|
445 break; |
|
446 } |
|
447 |
|
448 if (domain->data_size != data.data_size) { |
|
449 EC_ERR("Data size mismatch %u/%u!\n", |
|
450 data.data_size, domain->data_size); |
|
451 retval = -EFAULT; |
|
452 break; |
|
453 } |
|
454 |
|
455 if (copy_to_user((void __user *) data.target, domain->data, |
|
456 domain->data_size)) |
|
457 retval = -EFAULT; |
|
458 break; |
|
459 } |
|
460 |
|
461 case EC_IOCTL_SET_DEBUG: |
|
462 if (!(filp->f_mode & FMODE_WRITE)) |
1250 if (!(filp->f_mode & FMODE_WRITE)) |
463 return -EPERM; |
1251 return -EPERM; |
464 if (ec_master_debug_level(master, (unsigned int) arg)) |
1252 return ec_cdev_ioctl_master_debug(master, arg); |
465 retval = -EINVAL; |
|
466 break; |
|
467 |
|
468 case EC_IOCTL_SLAVE_STATE: |
1253 case EC_IOCTL_SLAVE_STATE: |
469 { |
1254 if (!(filp->f_mode & FMODE_WRITE)) |
470 ec_ioctl_slave_state_t data; |
1255 return -EPERM; |
471 ec_slave_t *slave; |
1256 return ec_cdev_ioctl_slave_state(master, arg); |
472 |
1257 case EC_IOCTL_SLAVE_SDO: |
473 if (!(filp->f_mode & FMODE_WRITE)) |
1258 return ec_cdev_ioctl_slave_sdo(master, arg); |
474 return -EPERM; |
1259 case EC_IOCTL_SLAVE_SDO_ENTRY: |
475 |
1260 return ec_cdev_ioctl_slave_sdo_entry(master, arg); |
476 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { |
1261 case EC_IOCTL_SLAVE_SDO_UPLOAD: |
477 retval = -EFAULT; |
1262 return ec_cdev_ioctl_slave_sdo_upload(master, arg); |
478 break; |
1263 case EC_IOCTL_SLAVE_SDO_DOWNLOAD: |
479 } |
1264 if (!(filp->f_mode & FMODE_WRITE)) |
480 |
1265 return -EPERM; |
481 if (!(slave = ec_master_find_slave( |
1266 return ec_cdev_ioctl_slave_sdo_download(master, arg); |
482 master, 0, data.slave_position))) { |
1267 case EC_IOCTL_SLAVE_SII_READ: |
483 EC_ERR("Slave %u does not exist!\n", data.slave_position); |
1268 return ec_cdev_ioctl_slave_sii_read(master, arg); |
484 retval = -EINVAL; |
1269 case EC_IOCTL_SLAVE_SII_WRITE: |
485 break; |
1270 if (!(filp->f_mode & FMODE_WRITE)) |
486 } |
1271 return -EPERM; |
487 |
1272 return ec_cdev_ioctl_slave_sii_write(master, arg); |
488 ec_slave_request_state(slave, data.requested_state); |
|
489 break; |
|
490 } |
|
491 |
|
492 case EC_IOCTL_SDO: |
|
493 { |
|
494 ec_ioctl_sdo_t data; |
|
495 const ec_slave_t *slave; |
|
496 const ec_sdo_t *sdo; |
|
497 |
|
498 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { |
|
499 retval = -EFAULT; |
|
500 break; |
|
501 } |
|
502 |
|
503 if (!(slave = ec_master_find_slave( |
|
504 master, 0, data.slave_position))) { |
|
505 EC_ERR("Slave %u does not exist!\n", data.slave_position); |
|
506 retval = -EINVAL; |
|
507 break; |
|
508 } |
|
509 |
|
510 if (!(sdo = ec_slave_get_sdo_by_pos_const( |
|
511 slave, data.sdo_position))) { |
|
512 EC_ERR("Sdo %u does not exist in slave %u!\n", |
|
513 data.sdo_position, data.slave_position); |
|
514 retval = -EINVAL; |
|
515 break; |
|
516 } |
|
517 |
|
518 data.sdo_index = sdo->index; |
|
519 data.max_subindex = sdo->max_subindex; |
|
520 |
|
521 if (sdo->name) { |
|
522 strncpy(data.name, sdo->name, EC_IOCTL_STRING_SIZE); |
|
523 data.name[EC_IOCTL_STRING_SIZE - 1] = 0; |
|
524 } else { |
|
525 data.name[0] = 0; |
|
526 } |
|
527 |
|
528 if (copy_to_user((void __user *) arg, &data, sizeof(data))) |
|
529 retval = -EFAULT; |
|
530 break; |
|
531 } |
|
532 |
|
533 case EC_IOCTL_SDO_ENTRY: |
|
534 { |
|
535 ec_ioctl_sdo_entry_t data; |
|
536 const ec_slave_t *slave; |
|
537 const ec_sdo_t *sdo; |
|
538 const ec_sdo_entry_t *entry; |
|
539 |
|
540 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { |
|
541 retval = -EFAULT; |
|
542 break; |
|
543 } |
|
544 |
|
545 if (!(slave = ec_master_find_slave( |
|
546 master, 0, data.slave_position))) { |
|
547 EC_ERR("Slave %u does not exist!\n", data.slave_position); |
|
548 retval = -EINVAL; |
|
549 break; |
|
550 } |
|
551 |
|
552 if (data.sdo_spec <= 0) { |
|
553 if (!(sdo = ec_slave_get_sdo_by_pos_const( |
|
554 slave, -data.sdo_spec))) { |
|
555 EC_ERR("Sdo %u does not exist in slave %u!\n", |
|
556 -data.sdo_spec, data.slave_position); |
|
557 retval = -EINVAL; |
|
558 break; |
|
559 } |
|
560 } else { |
|
561 if (!(sdo = ec_slave_get_sdo_const( |
|
562 slave, data.sdo_spec))) { |
|
563 EC_ERR("Sdo 0x%04X does not exist in slave %u!\n", |
|
564 data.sdo_spec, data.slave_position); |
|
565 retval = -EINVAL; |
|
566 break; |
|
567 } |
|
568 } |
|
569 |
|
570 if (!(entry = ec_sdo_get_entry_const( |
|
571 sdo, data.sdo_entry_subindex))) { |
|
572 EC_ERR("Sdo entry 0x%04X:%02X does not exist " |
|
573 "in slave %u!\n", sdo->index, |
|
574 data.sdo_entry_subindex, data.slave_position); |
|
575 retval = -EINVAL; |
|
576 break; |
|
577 } |
|
578 |
|
579 data.data_type = entry->data_type; |
|
580 data.bit_length = entry->bit_length; |
|
581 |
|
582 if (entry->description) { |
|
583 strncpy(data.description, entry->description, |
|
584 EC_IOCTL_STRING_SIZE); |
|
585 data.description[EC_IOCTL_STRING_SIZE - 1] |
|
586 = 0; |
|
587 } else { |
|
588 data.description[0] = 0; |
|
589 } |
|
590 |
|
591 if (copy_to_user((void __user *) arg, &data, sizeof(data))) |
|
592 retval = -EFAULT; |
|
593 break; |
|
594 } |
|
595 |
|
596 case EC_IOCTL_SDO_UPLOAD: |
|
597 { |
|
598 ec_ioctl_sdo_upload_t data; |
|
599 ec_master_sdo_request_t request; |
|
600 |
|
601 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { |
|
602 retval = -EFAULT; |
|
603 break; |
|
604 } |
|
605 |
|
606 if (!(request.slave = ec_master_find_slave( |
|
607 master, 0, data.slave_position))) { |
|
608 EC_ERR("Slave %u does not exist!\n", data.slave_position); |
|
609 retval = -EINVAL; |
|
610 break; |
|
611 } |
|
612 |
|
613 ec_sdo_request_init(&request.req); |
|
614 ec_sdo_request_address(&request.req, |
|
615 data.sdo_index, data.sdo_entry_subindex); |
|
616 ecrt_sdo_request_read(&request.req); |
|
617 |
|
618 // schedule request. |
|
619 down(&master->sdo_sem); |
|
620 list_add_tail(&request.list, &master->slave_sdo_requests); |
|
621 up(&master->sdo_sem); |
|
622 |
|
623 // wait for processing through FSM |
|
624 if (wait_event_interruptible(master->sdo_queue, |
|
625 request.req.state != EC_REQUEST_QUEUED)) { |
|
626 // interrupted by signal |
|
627 down(&master->sdo_sem); |
|
628 if (request.req.state == EC_REQUEST_QUEUED) { |
|
629 list_del(&request.req.list); |
|
630 up(&master->sdo_sem); |
|
631 ec_sdo_request_clear(&request.req); |
|
632 retval = -EINTR; |
|
633 break; |
|
634 } |
|
635 // request already processing: interrupt not possible. |
|
636 up(&master->sdo_sem); |
|
637 } |
|
638 |
|
639 // wait until master FSM has finished processing |
|
640 wait_event(master->sdo_queue, request.req.state != EC_REQUEST_BUSY); |
|
641 |
|
642 data.abort_code = request.req.abort_code; |
|
643 |
|
644 if (request.req.state != EC_REQUEST_SUCCESS) { |
|
645 data.data_size = 0; |
|
646 retval = -EIO; |
|
647 } else { |
|
648 if (request.req.data_size > data.target_size) { |
|
649 EC_ERR("Buffer too small.\n"); |
|
650 ec_sdo_request_clear(&request.req); |
|
651 retval = -EOVERFLOW; |
|
652 break; |
|
653 } |
|
654 data.data_size = request.req.data_size; |
|
655 |
|
656 if (copy_to_user((void __user *) data.target, |
|
657 request.req.data, data.data_size)) { |
|
658 ec_sdo_request_clear(&request.req); |
|
659 retval = -EFAULT; |
|
660 break; |
|
661 } |
|
662 } |
|
663 |
|
664 if (__copy_to_user((void __user *) arg, &data, sizeof(data))) { |
|
665 retval = -EFAULT; |
|
666 } |
|
667 |
|
668 ec_sdo_request_clear(&request.req); |
|
669 break; |
|
670 } |
|
671 |
|
672 case EC_IOCTL_SDO_DOWNLOAD: |
|
673 { |
|
674 ec_ioctl_sdo_download_t data; |
|
675 ec_master_sdo_request_t request; |
|
676 |
|
677 if (!(filp->f_mode & FMODE_WRITE)) |
|
678 return -EPERM; |
|
679 |
|
680 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { |
|
681 retval = -EFAULT; |
|
682 break; |
|
683 } |
|
684 |
|
685 if (!(request.slave = ec_master_find_slave( |
|
686 master, 0, data.slave_position))) { |
|
687 EC_ERR("Slave %u does not exist!\n", data.slave_position); |
|
688 retval = -EINVAL; |
|
689 break; |
|
690 } |
|
691 |
|
692 // copy data to download |
|
693 if (!data.data_size) { |
|
694 EC_ERR("Zero data size!\n"); |
|
695 retval = -EINVAL; |
|
696 break; |
|
697 } |
|
698 |
|
699 ec_sdo_request_init(&request.req); |
|
700 ec_sdo_request_address(&request.req, |
|
701 data.sdo_index, data.sdo_entry_subindex); |
|
702 if (ec_sdo_request_alloc(&request.req, data.data_size)) { |
|
703 ec_sdo_request_clear(&request.req); |
|
704 retval = -ENOMEM; |
|
705 break; |
|
706 } |
|
707 if (copy_from_user(request.req.data, |
|
708 (void __user *) data.data, data.data_size)) { |
|
709 ec_sdo_request_clear(&request.req); |
|
710 retval = -EFAULT; |
|
711 break; |
|
712 } |
|
713 request.req.data_size = data.data_size; |
|
714 ecrt_sdo_request_write(&request.req); |
|
715 |
|
716 // schedule request. |
|
717 down(&master->sdo_sem); |
|
718 list_add_tail(&request.list, &master->slave_sdo_requests); |
|
719 up(&master->sdo_sem); |
|
720 |
|
721 // wait for processing through FSM |
|
722 if (wait_event_interruptible(master->sdo_queue, |
|
723 request.req.state != EC_REQUEST_QUEUED)) { |
|
724 // interrupted by signal |
|
725 down(&master->sdo_sem); |
|
726 if (request.req.state == EC_REQUEST_QUEUED) { |
|
727 list_del(&request.req.list); |
|
728 up(&master->sdo_sem); |
|
729 ec_sdo_request_clear(&request.req); |
|
730 retval = -EINTR; |
|
731 break; |
|
732 } |
|
733 // request already processing: interrupt not possible. |
|
734 up(&master->sdo_sem); |
|
735 } |
|
736 |
|
737 // wait until master FSM has finished processing |
|
738 wait_event(master->sdo_queue, request.req.state != EC_REQUEST_BUSY); |
|
739 |
|
740 data.abort_code = request.req.abort_code; |
|
741 |
|
742 if (request.req.state != EC_REQUEST_SUCCESS) { |
|
743 retval = -EIO; |
|
744 } |
|
745 |
|
746 if (__copy_to_user((void __user *) arg, &data, sizeof(data))) { |
|
747 retval = -EFAULT; |
|
748 } |
|
749 |
|
750 ec_sdo_request_clear(&request.req); |
|
751 break; |
|
752 } |
|
753 |
|
754 case EC_IOCTL_SII_READ: |
|
755 { |
|
756 ec_ioctl_sii_t data; |
|
757 const ec_slave_t *slave; |
|
758 |
|
759 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { |
|
760 retval = -EFAULT; |
|
761 break; |
|
762 } |
|
763 |
|
764 if (!(slave = ec_master_find_slave( |
|
765 master, 0, data.slave_position))) { |
|
766 EC_ERR("Slave %u does not exist!\n", data.slave_position); |
|
767 retval = -EINVAL; |
|
768 break; |
|
769 } |
|
770 |
|
771 if (!data.nwords |
|
772 || data.offset + data.nwords > slave->sii_nwords) { |
|
773 EC_ERR("Invalid SII read offset/size %u/%u for slave " |
|
774 "SII size %u!\n", data.offset, |
|
775 data.nwords, slave->sii_nwords); |
|
776 retval = -EINVAL; |
|
777 break; |
|
778 } |
|
779 |
|
780 if (copy_to_user((void __user *) data.words, |
|
781 slave->sii_words + data.offset, data.nwords * 2)) |
|
782 retval = -EFAULT; |
|
783 break; |
|
784 } |
|
785 |
|
786 case EC_IOCTL_SII_WRITE: |
|
787 { |
|
788 ec_ioctl_sii_t data; |
|
789 ec_slave_t *slave; |
|
790 unsigned int byte_size; |
|
791 uint16_t *words; |
|
792 |
|
793 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { |
|
794 retval = -EFAULT; |
|
795 break; |
|
796 } |
|
797 |
|
798 if (!(slave = ec_master_find_slave( |
|
799 master, 0, data.slave_position))) { |
|
800 EC_ERR("Slave %u does not exist!\n", data.slave_position); |
|
801 retval = -EINVAL; |
|
802 break; |
|
803 } |
|
804 |
|
805 if (!data.nwords) |
|
806 break; |
|
807 |
|
808 byte_size = sizeof(uint16_t) * data.nwords; |
|
809 if (!(words = kmalloc(byte_size, GFP_KERNEL))) { |
|
810 EC_ERR("Failed to allocate %u bytes for SII contents.\n", |
|
811 byte_size); |
|
812 retval = -ENOMEM; |
|
813 break; |
|
814 } |
|
815 |
|
816 if (copy_from_user(words, |
|
817 (void __user *) data.words, byte_size)) { |
|
818 retval = -EFAULT; |
|
819 kfree(words); |
|
820 break; |
|
821 } |
|
822 |
|
823 if (ec_slave_write_sii(slave, |
|
824 data.offset, data.nwords, words)) |
|
825 retval = -EIO; |
|
826 |
|
827 kfree(words); |
|
828 break; |
|
829 } |
|
830 |
|
831 case EC_IOCTL_CONFIG: |
1273 case EC_IOCTL_CONFIG: |
832 { |
1274 return ec_cdev_ioctl_config(master, arg); |
833 ec_ioctl_config_t data; |
|
834 const ec_slave_config_t *sc; |
|
835 uint8_t i; |
|
836 |
|
837 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { |
|
838 retval = -EFAULT; |
|
839 break; |
|
840 } |
|
841 |
|
842 if (!(sc = ec_master_get_config_const( |
|
843 master, data.config_index))) { |
|
844 EC_ERR("Slave config %u does not exist!\n", |
|
845 data.config_index); |
|
846 retval = -EINVAL; |
|
847 break; |
|
848 } |
|
849 |
|
850 data.alias = sc->alias; |
|
851 data.position = sc->position; |
|
852 data.vendor_id = sc->vendor_id; |
|
853 data.product_code = sc->product_code; |
|
854 for (i = 0; i < EC_MAX_SYNCS; i++) { |
|
855 data.syncs[i].dir = sc->sync_configs[i].dir; |
|
856 data.syncs[i].pdo_count = |
|
857 ec_pdo_list_count(&sc->sync_configs[i].pdos); |
|
858 } |
|
859 data.sdo_count = ec_slave_config_sdo_count(sc); |
|
860 data.attached = sc->slave != NULL; |
|
861 data.operational = sc->slave && |
|
862 sc->slave->current_state == EC_SLAVE_STATE_OP; |
|
863 |
|
864 if (copy_to_user((void __user *) arg, &data, sizeof(data))) |
|
865 retval = -EFAULT; |
|
866 break; |
|
867 } |
|
868 |
|
869 case EC_IOCTL_CONFIG_PDO: |
1275 case EC_IOCTL_CONFIG_PDO: |
870 { |
1276 return ec_cdev_ioctl_config_pdo(master, arg); |
871 ec_ioctl_config_pdo_t data; |
|
872 const ec_slave_config_t *sc; |
|
873 const ec_pdo_t *pdo; |
|
874 |
|
875 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { |
|
876 retval = -EFAULT; |
|
877 break; |
|
878 } |
|
879 |
|
880 if (!(sc = ec_master_get_config_const( |
|
881 master, data.config_index))) { |
|
882 EC_ERR("Slave config %u does not exist!\n", |
|
883 data.config_index); |
|
884 retval = -EINVAL; |
|
885 break; |
|
886 } |
|
887 |
|
888 if (data.sync_index >= EC_MAX_SYNCS) { |
|
889 EC_ERR("Invalid sync manager index %u!\n", |
|
890 data.sync_index); |
|
891 retval = -EINVAL; |
|
892 break; |
|
893 } |
|
894 |
|
895 if (!(pdo = ec_pdo_list_find_pdo_by_pos_const( |
|
896 &sc->sync_configs[data.sync_index].pdos, |
|
897 data.pdo_pos))) { |
|
898 EC_ERR("Invalid Pdo position!\n"); |
|
899 retval = -EINVAL; |
|
900 break; |
|
901 } |
|
902 |
|
903 data.index = pdo->index; |
|
904 data.entry_count = ec_pdo_entry_count(pdo); |
|
905 |
|
906 if (pdo->name) { |
|
907 strncpy(data.name, pdo->name, EC_IOCTL_STRING_SIZE); |
|
908 data.name[EC_IOCTL_STRING_SIZE - 1] = 0; |
|
909 } else { |
|
910 data.name[0] = 0; |
|
911 } |
|
912 |
|
913 if (copy_to_user((void __user *) arg, &data, sizeof(data))) |
|
914 retval = -EFAULT; |
|
915 break; |
|
916 } |
|
917 |
|
918 case EC_IOCTL_CONFIG_PDO_ENTRY: |
1277 case EC_IOCTL_CONFIG_PDO_ENTRY: |
919 { |
1278 return ec_cdev_ioctl_config_pdo_entry(master, arg); |
920 ec_ioctl_config_pdo_entry_t data; |
|
921 const ec_slave_config_t *sc; |
|
922 const ec_pdo_t *pdo; |
|
923 const ec_pdo_entry_t *entry; |
|
924 |
|
925 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { |
|
926 retval = -EFAULT; |
|
927 break; |
|
928 } |
|
929 |
|
930 if (!(sc = ec_master_get_config_const( |
|
931 master, data.config_index))) { |
|
932 EC_ERR("Slave config %u does not exist!\n", |
|
933 data.config_index); |
|
934 retval = -EINVAL; |
|
935 break; |
|
936 } |
|
937 |
|
938 if (data.sync_index >= EC_MAX_SYNCS) { |
|
939 EC_ERR("Invalid sync manager index %u!\n", |
|
940 data.sync_index); |
|
941 retval = -EINVAL; |
|
942 break; |
|
943 } |
|
944 |
|
945 if (!(pdo = ec_pdo_list_find_pdo_by_pos_const( |
|
946 &sc->sync_configs[data.sync_index].pdos, |
|
947 data.pdo_pos))) { |
|
948 EC_ERR("Invalid Pdo position!\n"); |
|
949 retval = -EINVAL; |
|
950 break; |
|
951 } |
|
952 |
|
953 if (!(entry = ec_pdo_find_entry_by_pos_const( |
|
954 pdo, data.entry_pos))) { |
|
955 EC_ERR("Entry not found!\n"); |
|
956 retval = -EINVAL; |
|
957 break; |
|
958 } |
|
959 |
|
960 data.index = entry->index; |
|
961 data.subindex = entry->subindex; |
|
962 data.bit_length = entry->bit_length; |
|
963 if (entry->name) { |
|
964 strncpy(data.name, entry->name, EC_IOCTL_STRING_SIZE); |
|
965 data.name[EC_IOCTL_STRING_SIZE - 1] = 0; |
|
966 } else { |
|
967 data.name[0] = 0; |
|
968 } |
|
969 |
|
970 if (copy_to_user((void __user *) arg, &data, sizeof(data))) |
|
971 retval = -EFAULT; |
|
972 break; |
|
973 } |
|
974 |
|
975 case EC_IOCTL_CONFIG_SDO: |
1279 case EC_IOCTL_CONFIG_SDO: |
976 { |
1280 return ec_cdev_ioctl_config_sdo(master, arg); |
977 ec_ioctl_config_sdo_t data; |
|
978 const ec_slave_config_t *sc; |
|
979 const ec_sdo_request_t *req; |
|
980 |
|
981 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { |
|
982 retval = -EFAULT; |
|
983 break; |
|
984 } |
|
985 |
|
986 if (!(sc = ec_master_get_config_const( |
|
987 master, data.config_index))) { |
|
988 EC_ERR("Slave config %u does not exist!\n", |
|
989 data.config_index); |
|
990 retval = -EINVAL; |
|
991 break; |
|
992 } |
|
993 |
|
994 if (!(req = ec_slave_config_get_sdo_by_pos_const( |
|
995 sc, data.sdo_pos))) { |
|
996 EC_ERR("Invalid Sdo position!\n"); |
|
997 retval = -EINVAL; |
|
998 break; |
|
999 } |
|
1000 |
|
1001 data.index = req->index; |
|
1002 data.subindex = req->subindex; |
|
1003 data.size = req->data_size; |
|
1004 memcpy(&data.data, req->data, min((u32) data.size, (u32) 4)); |
|
1005 |
|
1006 if (copy_to_user((void __user *) arg, &data, sizeof(data))) |
|
1007 retval = -EFAULT; |
|
1008 break; |
|
1009 } |
|
1010 |
|
1011 default: |
1281 default: |
1012 retval = -ENOTTY; |
1282 return -ENOTTY; |
1013 } |
1283 } |
1014 |
1284 } |
1015 up(&master->master_sem); |
1285 |
1016 return retval; |
1286 /*****************************************************************************/ |
1017 } |
|
1018 |
|
1019 /*****************************************************************************/ |
|