50 /** \cond */ |
52 /** \cond */ |
51 |
53 |
52 int eccdev_open(struct inode *, struct file *); |
54 int eccdev_open(struct inode *, struct file *); |
53 int eccdev_release(struct inode *, struct file *); |
55 int eccdev_release(struct inode *, struct file *); |
54 long eccdev_ioctl(struct file *, unsigned int, unsigned long); |
56 long eccdev_ioctl(struct file *, unsigned int, unsigned long); |
|
57 int eccdev_mmap(struct file *, struct vm_area_struct *); |
|
58 |
|
59 static struct page *eccdev_vma_nopage( |
|
60 struct vm_area_struct *, unsigned long, int *); |
55 |
61 |
56 /*****************************************************************************/ |
62 /*****************************************************************************/ |
57 |
63 |
58 static struct file_operations eccdev_fops = { |
64 static struct file_operations eccdev_fops = { |
59 .owner = THIS_MODULE, |
65 .owner = THIS_MODULE, |
60 .open = eccdev_open, |
66 .open = eccdev_open, |
61 .release = eccdev_release, |
67 .release = eccdev_release, |
62 .unlocked_ioctl = eccdev_ioctl |
68 .unlocked_ioctl = eccdev_ioctl, |
|
69 .mmap = eccdev_mmap |
|
70 }; |
|
71 |
|
72 struct vm_operations_struct eccdev_vm_ops = { |
|
73 .nopage = eccdev_vma_nopage |
63 }; |
74 }; |
64 |
75 |
65 /** \endcond */ |
76 /** \endcond */ |
66 |
77 |
67 /*****************************************************************************/ |
78 /*****************************************************************************/ |
1460 ec_master_t *master, /**< EtherCAT master. */ |
1473 ec_master_t *master, /**< EtherCAT master. */ |
1461 unsigned long arg, /**< ioctl() argument. */ |
1474 unsigned long arg, /**< ioctl() argument. */ |
1462 ec_cdev_priv_t *priv /**< Private data structure of file handle. */ |
1475 ec_cdev_priv_t *priv /**< Private data structure of file handle. */ |
1463 ) |
1476 ) |
1464 { |
1477 { |
|
1478 ec_domain_t *domain; |
|
1479 off_t offset; |
|
1480 |
1465 if (unlikely(!priv->requested)) |
1481 if (unlikely(!priv->requested)) |
1466 return -EPERM; |
1482 return -EPERM; |
1467 |
1483 |
|
1484 /* Get the sum of the domains' process data sizes. */ |
|
1485 |
|
1486 priv->process_data_size = 0; |
|
1487 |
|
1488 if (down_interruptible(&master->master_sem)) |
|
1489 return -EINTR; |
|
1490 |
|
1491 list_for_each_entry(domain, &master->domains, list) { |
|
1492 priv->process_data_size += ecrt_domain_size(domain); |
|
1493 } |
|
1494 |
|
1495 up(&master->master_sem); |
|
1496 |
|
1497 if (priv->process_data_size) { |
|
1498 priv->process_data = vmalloc(priv->process_data_size); |
|
1499 if (!priv->process_data) { |
|
1500 priv->process_data_size = 0; |
|
1501 return -ENOMEM; |
|
1502 } |
|
1503 |
|
1504 /* Set the memory as external process data memory for the domains. */ |
|
1505 |
|
1506 offset = 0; |
|
1507 list_for_each_entry(domain, &master->domains, list) { |
|
1508 ecrt_domain_external_memory(domain, priv->process_data + offset); |
|
1509 offset += ecrt_domain_size(domain); |
|
1510 } |
|
1511 } |
|
1512 |
1468 if (ecrt_master_activate(master)) |
1513 if (ecrt_master_activate(master)) |
1469 return -EIO; |
1514 return -EIO; |
|
1515 |
|
1516 if (copy_to_user((void __user *) arg, |
|
1517 &priv->process_data_size, sizeof(size_t))) |
|
1518 return -EFAULT; |
1470 |
1519 |
1471 return 0; |
1520 return 0; |
1472 } |
1521 } |
1473 |
1522 |
1474 /*****************************************************************************/ |
1523 /*****************************************************************************/ |
1786 data.size); |
1835 data.size); |
1787 kfree(sdo_data); |
1836 kfree(sdo_data); |
1788 return ret; |
1837 return ret; |
1789 } |
1838 } |
1790 |
1839 |
|
1840 /*****************************************************************************/ |
|
1841 |
|
1842 /** Gets the domain's offset in the total process data. |
|
1843 */ |
|
1844 int ec_cdev_ioctl_domain_offset( |
|
1845 ec_master_t *master, /**< EtherCAT master. */ |
|
1846 unsigned long arg, /**< ioctl() argument. */ |
|
1847 ec_cdev_priv_t *priv /**< Private data structure of file handle. */ |
|
1848 ) |
|
1849 { |
|
1850 int offset = 0; |
|
1851 const ec_domain_t *domain; |
|
1852 |
|
1853 if (unlikely(!priv->requested)) |
|
1854 return -EPERM; |
|
1855 |
|
1856 if (down_interruptible(&master->master_sem)) { |
|
1857 return -EINTR; |
|
1858 } |
|
1859 |
|
1860 list_for_each_entry(domain, &master->domains, list) { |
|
1861 if (domain->index == arg) { |
|
1862 up(&master->master_sem); |
|
1863 return offset; |
|
1864 } |
|
1865 offset += ecrt_domain_size(domain); |
|
1866 } |
|
1867 |
|
1868 up(&master->master_sem); |
|
1869 return -ESRCH; |
|
1870 } |
|
1871 |
|
1872 /*****************************************************************************/ |
|
1873 |
|
1874 /** Process the domain. |
|
1875 */ |
|
1876 int ec_cdev_ioctl_domain_process( |
|
1877 ec_master_t *master, /**< EtherCAT master. */ |
|
1878 unsigned long arg, /**< ioctl() argument. */ |
|
1879 ec_cdev_priv_t *priv /**< Private data structure of file handle. */ |
|
1880 ) |
|
1881 { |
|
1882 ec_domain_t *domain; |
|
1883 |
|
1884 if (unlikely(!priv->requested)) |
|
1885 return -EPERM; |
|
1886 |
|
1887 if (down_interruptible(&master->master_sem)) |
|
1888 return -EINTR; |
|
1889 |
|
1890 if (!(domain = ec_master_find_domain(master, arg))) { |
|
1891 up(&master->master_sem); |
|
1892 return -ESRCH; |
|
1893 } |
|
1894 |
|
1895 ecrt_domain_process(domain); |
|
1896 up(&master->master_sem); |
|
1897 return 0; |
|
1898 } |
|
1899 |
|
1900 /*****************************************************************************/ |
|
1901 |
|
1902 /** Queue the domain. |
|
1903 */ |
|
1904 int ec_cdev_ioctl_domain_queue( |
|
1905 ec_master_t *master, /**< EtherCAT master. */ |
|
1906 unsigned long arg, /**< ioctl() argument. */ |
|
1907 ec_cdev_priv_t *priv /**< Private data structure of file handle. */ |
|
1908 ) |
|
1909 { |
|
1910 ec_domain_t *domain; |
|
1911 |
|
1912 if (unlikely(!priv->requested)) |
|
1913 return -EPERM; |
|
1914 |
|
1915 if (down_interruptible(&master->master_sem)) |
|
1916 return -EINTR; |
|
1917 |
|
1918 if (!(domain = ec_master_find_domain(master, arg))) { |
|
1919 up(&master->master_sem); |
|
1920 return -ESRCH; |
|
1921 } |
|
1922 |
|
1923 ecrt_domain_queue(domain); |
|
1924 up(&master->master_sem); |
|
1925 return 0; |
|
1926 } |
|
1927 |
1791 /****************************************************************************** |
1928 /****************************************************************************** |
1792 * File operations |
1929 * File operations |
1793 *****************************************************************************/ |
1930 *****************************************************************************/ |
1794 |
1931 |
1795 /** Called when the cdev is opened. |
1932 /** Called when the cdev is opened. |
1824 ec_cdev_priv_t *priv = (ec_cdev_priv_t *) filp->private_data; |
1963 ec_cdev_priv_t *priv = (ec_cdev_priv_t *) filp->private_data; |
1825 ec_master_t *master = priv->cdev->master; |
1964 ec_master_t *master = priv->cdev->master; |
1826 |
1965 |
1827 if (priv->requested) |
1966 if (priv->requested) |
1828 ecrt_release_master(master); |
1967 ecrt_release_master(master); |
|
1968 |
|
1969 if (priv->process_data) |
|
1970 vfree(priv->process_data); |
1829 |
1971 |
1830 if (master->debug_level) |
1972 if (master->debug_level) |
1831 EC_DBG("File closed.\n"); |
1973 EC_DBG("File closed.\n"); |
1832 kfree(priv); |
1974 kfree(priv); |
1833 return 0; |
1975 return 0; |
1951 return ec_cdev_ioctl_sc_reg_pdo_entry(master, arg, priv); |
2093 return ec_cdev_ioctl_sc_reg_pdo_entry(master, arg, priv); |
1952 case EC_IOCTL_SC_SDO: |
2094 case EC_IOCTL_SC_SDO: |
1953 if (!(filp->f_mode & FMODE_WRITE)) |
2095 if (!(filp->f_mode & FMODE_WRITE)) |
1954 return -EPERM; |
2096 return -EPERM; |
1955 return ec_cdev_ioctl_sc_sdo(master, arg, priv); |
2097 return ec_cdev_ioctl_sc_sdo(master, arg, priv); |
|
2098 case EC_IOCTL_DOMAIN_OFFSET: |
|
2099 return ec_cdev_ioctl_domain_offset(master, arg, priv); |
|
2100 case EC_IOCTL_DOMAIN_PROCESS: |
|
2101 if (!(filp->f_mode & FMODE_WRITE)) |
|
2102 return -EPERM; |
|
2103 return ec_cdev_ioctl_domain_process(master, arg, priv); |
|
2104 case EC_IOCTL_DOMAIN_QUEUE: |
|
2105 if (!(filp->f_mode & FMODE_WRITE)) |
|
2106 return -EPERM; |
|
2107 return ec_cdev_ioctl_domain_queue(master, arg, priv); |
1956 default: |
2108 default: |
1957 return -ENOTTY; |
2109 return -ENOTTY; |
1958 } |
2110 } |
1959 } |
2111 } |
1960 |
2112 |
1961 /*****************************************************************************/ |
2113 /*****************************************************************************/ |
|
2114 |
|
2115 int eccdev_mmap( |
|
2116 struct file *filp, |
|
2117 struct vm_area_struct *vma |
|
2118 ) |
|
2119 { |
|
2120 ec_cdev_priv_t *priv = (ec_cdev_priv_t *) filp->private_data; |
|
2121 |
|
2122 if (priv->cdev->master->debug_level) |
|
2123 EC_DBG("mmap()\n"); |
|
2124 |
|
2125 vma->vm_ops = &eccdev_vm_ops; |
|
2126 vma->vm_flags |= VM_RESERVED; /* Pages will not be swapped out */ |
|
2127 vma->vm_private_data = priv; |
|
2128 |
|
2129 return 0; |
|
2130 } |
|
2131 |
|
2132 /*****************************************************************************/ |
|
2133 |
|
2134 struct page *eccdev_vma_nopage( |
|
2135 struct vm_area_struct *vma, |
|
2136 unsigned long address, |
|
2137 int *type |
|
2138 ) |
|
2139 { |
|
2140 unsigned long offset; |
|
2141 struct page *page = NOPAGE_SIGBUS; |
|
2142 ec_cdev_priv_t *priv = (ec_cdev_priv_t *) vma->vm_private_data; |
|
2143 |
|
2144 offset = (address - vma->vm_start) + (vma->vm_pgoff << PAGE_SHIFT); |
|
2145 |
|
2146 if (offset >= priv->process_data_size) |
|
2147 return NOPAGE_SIGBUS; |
|
2148 |
|
2149 page = vmalloc_to_page(priv->process_data + offset); |
|
2150 |
|
2151 if (priv->cdev->master->debug_level) |
|
2152 EC_DBG("Nopage fault vma, address = %#lx, offset = %#lx, page = %p\n", |
|
2153 address, offset, page); |
|
2154 |
|
2155 get_page(page); |
|
2156 if (type) |
|
2157 *type = VM_FAULT_MINOR; |
|
2158 |
|
2159 return page; |
|
2160 } |
|
2161 |
|
2162 /*****************************************************************************/ |