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