master/cdev.c
changeset 1258 900f1124e8f8
parent 1255 38b7e05b20c1
child 1259 5f9d1abbee71
equal deleted inserted replaced
1257:9844ac126275 1258:900f1124e8f8
    37 */
    37 */
    38 
    38 
    39 /*****************************************************************************/
    39 /*****************************************************************************/
    40 
    40 
    41 #include <linux/module.h>
    41 #include <linux/module.h>
       
    42 #include <linux/vmalloc.h>
       
    43 #include <linux/mm.h>
    42 
    44 
    43 #include "cdev.h"
    45 #include "cdev.h"
    44 #include "master.h"
    46 #include "master.h"
    45 #include "slave_config.h"
    47 #include "slave_config.h"
    46 #include "ioctl.h"
    48 #include "ioctl.h"
    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 /*****************************************************************************/
    69 /** Private data structure for file handles.
    80 /** Private data structure for file handles.
    70  */
    81  */
    71 typedef struct {
    82 typedef struct {
    72     ec_cdev_t *cdev;
    83     ec_cdev_t *cdev;
    73     unsigned int requested;
    84     unsigned int requested;
       
    85     uint8_t *process_data;
       
    86     size_t process_data_size;
    74 } ec_cdev_priv_t;
    87 } ec_cdev_priv_t;
    75 
    88 
    76 /*****************************************************************************/
    89 /*****************************************************************************/
    77 
    90 
    78 /** Constructor.
    91 /** Constructor.
  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.
  1806         return -ENOMEM;
  1943         return -ENOMEM;
  1807     }
  1944     }
  1808 
  1945 
  1809     priv->cdev = cdev;
  1946     priv->cdev = cdev;
  1810     priv->requested = 0;
  1947     priv->requested = 0;
       
  1948     priv->process_data = NULL;
       
  1949     priv->process_data_size = 0;
  1811 
  1950 
  1812     filp->private_data = priv;
  1951     filp->private_data = priv;
  1813     if (master->debug_level)
  1952     if (master->debug_level)
  1814         EC_DBG("File opened.\n");
  1953         EC_DBG("File opened.\n");
  1815     return 0;
  1954     return 0;
  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 /*****************************************************************************/