836 ec_master_t *master, /**< EtherCAT master. */ |
836 ec_master_t *master, /**< EtherCAT master. */ |
837 unsigned long arg /**< ioctl() argument. */ |
837 unsigned long arg /**< ioctl() argument. */ |
838 ) |
838 ) |
839 { |
839 { |
840 ec_ioctl_slave_sdo_upload_t data; |
840 ec_ioctl_slave_sdo_upload_t data; |
841 ec_master_sdo_request_t request; |
841 uint8_t *target; |
842 int retval; |
842 int ret; |
843 |
843 |
844 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { |
844 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { |
845 return -EFAULT; |
845 return -EFAULT; |
846 } |
846 } |
847 |
847 |
848 ec_sdo_request_init(&request.req); |
848 if (!(target = kmalloc(data.target_size, GFP_KERNEL))) { |
849 ec_sdo_request_address(&request.req, |
849 EC_MASTER_ERR(master, "Failed to allocate %u bytes" |
850 data.sdo_index, data.sdo_entry_subindex); |
850 " for SDO upload.\n", data.target_size); |
851 ecrt_sdo_request_read(&request.req); |
851 return -ENOMEM; |
852 |
852 } |
853 if (down_interruptible(&master->master_sem)) |
853 |
854 return -EINTR; |
854 ret = ecrt_master_sdo_upload(master, data.slave_position, |
855 |
855 data.sdo_index, data.sdo_entry_subindex, target, |
856 if (!(request.slave = ec_master_find_slave( |
856 data.target_size, &data.data_size, &data.abort_code); |
857 master, 0, data.slave_position))) { |
857 |
858 up(&master->master_sem); |
858 if (!ret) { |
859 ec_sdo_request_clear(&request.req); |
|
860 EC_MASTER_ERR(master, "Slave %u does not exist!\n", |
|
861 data.slave_position); |
|
862 return -EINVAL; |
|
863 } |
|
864 |
|
865 EC_SLAVE_DBG(request.slave, 1, "Schedule SDO upload request.\n"); |
|
866 |
|
867 // schedule request. |
|
868 list_add_tail(&request.list, &request.slave->slave_sdo_requests); |
|
869 |
|
870 up(&master->master_sem); |
|
871 |
|
872 // wait for processing through FSM |
|
873 if (wait_event_interruptible(request.slave->sdo_queue, |
|
874 request.req.state != EC_INT_REQUEST_QUEUED)) { |
|
875 // interrupted by signal |
|
876 down(&master->master_sem); |
|
877 if (request.req.state == EC_INT_REQUEST_QUEUED) { |
|
878 list_del(&request.list); |
|
879 up(&master->master_sem); |
|
880 ec_sdo_request_clear(&request.req); |
|
881 return -EINTR; |
|
882 } |
|
883 // request already processing: interrupt not possible. |
|
884 up(&master->master_sem); |
|
885 } |
|
886 |
|
887 // wait until master FSM has finished processing |
|
888 wait_event(request.slave->sdo_queue, |
|
889 request.req.state != EC_INT_REQUEST_BUSY); |
|
890 |
|
891 EC_SLAVE_DBG(request.slave, 1, "Finished SDO upload request.\n"); |
|
892 |
|
893 data.abort_code = request.req.abort_code; |
|
894 |
|
895 if (request.req.state != EC_INT_REQUEST_SUCCESS) { |
|
896 data.data_size = 0; |
|
897 if (request.req.errno) { |
|
898 retval = -request.req.errno; |
|
899 } else { |
|
900 retval = -EIO; |
|
901 } |
|
902 } else { |
|
903 if (request.req.data_size > data.target_size) { |
|
904 EC_MASTER_ERR(master, "Buffer too small.\n"); |
|
905 ec_sdo_request_clear(&request.req); |
|
906 return -EOVERFLOW; |
|
907 } |
|
908 data.data_size = request.req.data_size; |
|
909 |
|
910 if (copy_to_user((void __user *) data.target, |
859 if (copy_to_user((void __user *) data.target, |
911 request.req.data, data.data_size)) { |
860 target, data.data_size)) { |
912 ec_sdo_request_clear(&request.req); |
861 kfree(target); |
913 return -EFAULT; |
862 return -EFAULT; |
914 } |
863 } |
915 retval = 0; |
864 } |
916 } |
865 |
|
866 kfree(target); |
|
867 |
|
868 if (__copy_to_user((void __user *) arg, &data, sizeof(data))) { |
|
869 return -EFAULT; |
|
870 } |
|
871 |
|
872 return 0; |
|
873 } |
|
874 |
|
875 /*****************************************************************************/ |
|
876 |
|
877 /** Download SDO. |
|
878 */ |
|
879 int ec_cdev_ioctl_slave_sdo_download( |
|
880 ec_master_t *master, /**< EtherCAT master. */ |
|
881 unsigned long arg /**< ioctl() argument. */ |
|
882 ) |
|
883 { |
|
884 ec_ioctl_slave_sdo_download_t data; |
|
885 uint8_t *sdo_data; |
|
886 int retval; |
|
887 |
|
888 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { |
|
889 return -EFAULT; |
|
890 } |
|
891 |
|
892 if (!(sdo_data = kmalloc(data.data_size, GFP_KERNEL))) { |
|
893 EC_MASTER_ERR(master, "Failed to allocate %u bytes" |
|
894 " for SDO download.\n", data.data_size); |
|
895 return -ENOMEM; |
|
896 } |
|
897 |
|
898 if (copy_from_user(sdo_data, (void __user *) data.data, data.data_size)) { |
|
899 kfree(sdo_data); |
|
900 return -EFAULT; |
|
901 } |
|
902 |
|
903 retval = ecrt_master_sdo_download(master, data.slave_position, |
|
904 data.sdo_index, data.sdo_entry_subindex, sdo_data, data.data_size, |
|
905 &data.abort_code); |
|
906 |
|
907 kfree(sdo_data); |
917 |
908 |
918 if (__copy_to_user((void __user *) arg, &data, sizeof(data))) { |
909 if (__copy_to_user((void __user *) arg, &data, sizeof(data))) { |
919 retval = -EFAULT; |
910 retval = -EFAULT; |
920 } |
911 } |
921 |
912 |
922 ec_sdo_request_clear(&request.req); |
|
923 return retval; |
|
924 } |
|
925 |
|
926 /*****************************************************************************/ |
|
927 |
|
928 /** Download SDO. |
|
929 */ |
|
930 int ec_cdev_ioctl_slave_sdo_download( |
|
931 ec_master_t *master, /**< EtherCAT master. */ |
|
932 unsigned long arg /**< ioctl() argument. */ |
|
933 ) |
|
934 { |
|
935 ec_ioctl_slave_sdo_download_t data; |
|
936 ec_master_sdo_request_t request; |
|
937 int retval; |
|
938 |
|
939 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { |
|
940 return -EFAULT; |
|
941 } |
|
942 |
|
943 // copy data to download |
|
944 if (!data.data_size) { |
|
945 EC_MASTER_ERR(master, "Zero data size!\n"); |
|
946 return -EINVAL; |
|
947 } |
|
948 |
|
949 ec_sdo_request_init(&request.req); |
|
950 ec_sdo_request_address(&request.req, |
|
951 data.sdo_index, data.sdo_entry_subindex); |
|
952 if (ec_sdo_request_alloc(&request.req, data.data_size)) { |
|
953 ec_sdo_request_clear(&request.req); |
|
954 return -ENOMEM; |
|
955 } |
|
956 if (copy_from_user(request.req.data, |
|
957 (void __user *) data.data, data.data_size)) { |
|
958 ec_sdo_request_clear(&request.req); |
|
959 return -EFAULT; |
|
960 } |
|
961 request.req.data_size = data.data_size; |
|
962 ecrt_sdo_request_write(&request.req); |
|
963 |
|
964 if (down_interruptible(&master->master_sem)) |
|
965 return -EINTR; |
|
966 |
|
967 if (!(request.slave = ec_master_find_slave( |
|
968 master, 0, data.slave_position))) { |
|
969 up(&master->master_sem); |
|
970 EC_MASTER_ERR(master, "Slave %u does not exist!\n", |
|
971 data.slave_position); |
|
972 ec_sdo_request_clear(&request.req); |
|
973 return -EINVAL; |
|
974 } |
|
975 |
|
976 EC_SLAVE_DBG(request.slave, 1, "Schedule SDO download request.\n"); |
|
977 |
|
978 // schedule request. |
|
979 list_add_tail(&request.list, &request.slave->slave_sdo_requests); |
|
980 |
|
981 up(&master->master_sem); |
|
982 |
|
983 // wait for processing through FSM |
|
984 if (wait_event_interruptible(request.slave->sdo_queue, |
|
985 request.req.state != EC_INT_REQUEST_QUEUED)) { |
|
986 // interrupted by signal |
|
987 down(&master->master_sem); |
|
988 if (request.req.state == EC_INT_REQUEST_QUEUED) { |
|
989 list_del(&request.list); |
|
990 up(&master->master_sem); |
|
991 ec_sdo_request_clear(&request.req); |
|
992 return -EINTR; |
|
993 } |
|
994 // request already processing: interrupt not possible. |
|
995 up(&master->master_sem); |
|
996 } |
|
997 |
|
998 // wait until master FSM has finished processing |
|
999 wait_event(request.slave->sdo_queue, |
|
1000 request.req.state != EC_INT_REQUEST_BUSY); |
|
1001 |
|
1002 EC_SLAVE_DBG(request.slave, 1, "Finished SDO download request.\n"); |
|
1003 |
|
1004 data.abort_code = request.req.abort_code; |
|
1005 |
|
1006 if (request.req.state == EC_INT_REQUEST_SUCCESS) { |
|
1007 retval = 0; |
|
1008 } else if (request.req.errno) { |
|
1009 retval = -request.req.errno; |
|
1010 } else { |
|
1011 retval = -EIO; |
|
1012 } |
|
1013 |
|
1014 if (__copy_to_user((void __user *) arg, &data, sizeof(data))) { |
|
1015 retval = -EFAULT; |
|
1016 } |
|
1017 |
|
1018 ec_sdo_request_clear(&request.req); |
|
1019 return retval; |
913 return retval; |
1020 } |
914 } |
1021 |
915 |
1022 /*****************************************************************************/ |
916 /*****************************************************************************/ |
1023 |
917 |