Hi Alessio, Jan has already provided such example on the list.

For your easy, I'm re-sending it to you.

Best Regards,

Rodrigo.

____________________________________________________________
Em Quinta 23 Fevereiro 2006 12:07, Alessio Igor Bogani escreveu:

>Hi All,
>
>Someone can post on mailing-list a simple usage example of
>rtdm_mmap_to_user()?
>Thanks.
>
>Best Regards,
>Alessio Igor Bogani
>
>
>_______________________________________________
>Xenomai-help mailing list
>[email protected]
>https://mail.gna.org/listinfo/xenomai-help
Index: include/rtdm/rtdm_driver.h
===================================================================
--- include/rtdm/rtdm_driver.h	(Revision 564)
+++ include/rtdm/rtdm_driver.h	(Arbeitskopie)
@@ -995,6 +995,12 @@
     xnfree(ptr);
 }
 
+int rtdm_mmap_to_user(rtdm_user_info_t *user_info, void *src_addr, size_t len,
+                      int prot, void **pptr,
+                      struct vm_operations_struct *vm_ops,
+                      void *vm_private_data);
+int rtdm_munmap(rtdm_user_info_t *user_info, void *ptr, size_t len);
+
 static inline int rtdm_read_user_ok(rtdm_user_info_t *user_info,
                                     const void __user *ptr, size_t size)
 {
Index: ksrc/skins/rtdm/drvlib.c
===================================================================
--- ksrc/skins/rtdm/drvlib.c	(Revision 564)
+++ ksrc/skins/rtdm/drvlib.c	(Arbeitskopie)
@@ -31,6 +31,7 @@
 
 
 #include <linux/delay.h>
+#include <linux/mman.h>
 
 #include <rtdm/rtdm_driver.h>
 
@@ -1286,7 +1287,7 @@
  * Rescheduling: never.
  */
 int rtdm_irq_disable(rtdm_irq_t *irq_handle);
-/** @} */
+/** @} Interrupt Management Services */
 
 
 /*!
@@ -1358,16 +1359,158 @@
  * environments.
  */
 void rtdm_nrtsig_pend(rtdm_nrtsig_t *nrt_sig);
-/** @} */
+/** @} Non-Real-Time Signalling Services */
 
+#endif /* DOXYGEN_CPP */
 
+
 /*!
  * @ingroup driverapi
  * @defgroup util Utility Services
  * @{
  */
 
+struct rtdm_mmap_data {
+    void *src_addr;
+    struct vm_operations_struct *vm_ops;
+    void *vm_private_data;
+};
+
+static int rtdm_mmap_buffer(struct file *filp, struct vm_area_struct *vma)
+{
+    struct rtdm_mmap_data *mmap_data = filp->private_data;
+
+    vma->vm_ops = mmap_data->vm_ops;
+    vma->vm_private_data = mmap_data->vm_private_data;
+
+    return xnarch_remap_page_range(vma, vma->vm_start,
+                                   virt_to_phys(mmap_data->src_addr),
+                                   vma->vm_end - vma->vm_start, PAGE_SHARED);
+}
+
+static struct file_operations rtdm_mmap_fops = {
+    .mmap = rtdm_mmap_buffer,
+};
+
 /**
+ * Map a kernel memory range into the address space of the user.
+ *
+ * @param[in] user_info User information pointer as passed to the invoked
+ * device operation handler
+ * @param[in] src_addr Kernel address to be mapped
+ * @param[in] len Length of the memory range
+ * @param[in] prot Protection flags for the user's memory range, typically
+ * either PROT_READ or PROT_READ|PROT_WRITE
+ * @param[in,out] pptr Address of a pointer containing the desired user
+ * address or NULL on entry and the finally assigned address on return
+ * @param[in] vm_ops vm_operations to be executed on the vma_area of the
+ * user memory range or NULL
+ * @param[in] vm_private_data Private data to be stored in the vma_area,
+ * primarily useful for vm_operation handlers
+ *
+ * @return 0 on success, otherwise:
+ *
+ * - -EXXX is returned if .
+ *
+ * @note RTDM supports two models for unmapping the user memory range again.
+ * One is explicite unmapping via rtdm_munmap(), either performed when the
+ * user requests it via an IOCTL etc. or when the related device is closed.
+ * The other is automatic unmapping, triggered by the user invoking standard
+ * munmap() or by the termination of the related process. To track release of
+ * the mapping and therefore relinquishment of the referenced physical memory,
+ * the caller of rtdm_mmap_to_user() can pass a vm_operations_struct on
+ * invocation, defining a close handler for the vm_area. See Linux
+ * documentaion (e.g. Linux Device Drivers book) on virtual memory management
+ * for details.
+ *
+ * Environments:
+ *
+ * This service can be called from:
+ *
+ * - Kernel module initialization/cleanup code
+ * - User-space task (non-RT)
+ *
+ * Rescheduling: possible.
+ */
+int rtdm_mmap_to_user(rtdm_user_info_t *user_info, void *src_addr, size_t len,
+                      int prot, void **pptr,
+                      struct vm_operations_struct *vm_ops,
+                      void *vm_private_data)
+{
+    struct rtdm_mmap_data   mmap_data = {src_addr, vm_ops, vm_private_data};
+    struct file             *filp;
+    struct file_operations  *old_fops;
+    void                    *old_priv_data;
+    void                    *user_ptr;
+
+    filp = filp_open("/dev/zero", O_RDWR, 0);
+    if (IS_ERR(filp))
+        return PTR_ERR(filp);
+
+    old_fops = filp->f_op;
+    filp->f_op = &rtdm_mmap_fops;
+
+    old_priv_data = filp->private_data;
+    filp->private_data = &mmap_data;
+
+    down_write(&user_info->mm->mmap_sem);
+    user_ptr = (void *)do_mmap(filp, (unsigned long)*pptr, len, prot,
+                               MAP_SHARED, 0);
+    up_write(&user_info->mm->mmap_sem);
+
+    filp->f_op = old_fops;
+    filp->private_data = old_priv_data;
+
+    filp_close(filp, user_info->files);
+
+    if (IS_ERR(user_ptr))
+        return PTR_ERR(user_ptr);
+
+    *pptr = user_ptr;
+    return 0;
+}
+
+EXPORT_SYMBOL(rtdm_mmap_to_user);
+
+
+/**
+ * Unmap a user memory range.
+ *
+ * @param[in] user_info User information pointer as passed to
+ * rtdm_mmap_to_user() when requesting to map the memory range
+ * @param[in] ptr User address or the memory range
+ * @param[in] len Length of the memory range
+ *
+ * @return 0 on success, otherwise:
+ *
+ * - -EXXX is returned if .
+ *
+ * Environments:
+ *
+ * This service can be called from:
+ *
+ * - Kernel module initialization/cleanup code
+ * - User-space task (non-RT)
+ *
+ * Rescheduling: possible.
+ */
+int rtdm_munmap(rtdm_user_info_t *user_info, void *ptr, size_t len)
+{
+    int err;
+
+    down_write(&user_info->mm->mmap_sem);
+    err = do_munmap(user_info->mm, (unsigned long)ptr, len);
+    up_write(&user_info->mm->mmap_sem);
+
+    return err;
+}
+
+EXPORT_SYMBOL(rtdm_munmap);
+
+
+#ifdef DOXYGEN_CPP /* Only used for doxygen doc generation */
+
+/**
  * Real-time safe message printing on kernel console
  *
  * @param[in] format Format string (conforming standard @c printf())
@@ -1583,6 +1726,6 @@
  */
 int rtdm_in_rt_context(void);
 
-/** @} */
+#endif /* DOXYGEN_CPP */
 
-#endif /* DOXYGEN_CPP */
+/** @} Utility Services */
#include <linux/mman.h>

#include <rtdm/rtdm_driver.h>


#define BUFFER_SIZE     100000


struct demodrv_context {
    void *buf;
};


static void demo_vm_close(struct vm_area_struct *vma)
{
    printk("releasing %p, data = %p\n", vma, vma->vm_private_data);
}


static struct vm_operations_struct mmap_ops = {
    .close = demo_vm_close,
};


int demo_open_rt(struct rtdm_dev_context    *context,
                 rtdm_user_info_t           *user_info,
                 int                        oflags)
{
    struct demodrv_context  *my_context;
    unsigned long vaddr;


    my_context = (struct demodrv_context *)context->dev_private;

    my_context->buf = kmalloc(BUFFER_SIZE, 0);
    /* mark pages reserved so that remap_pfn_range works */
    for (vaddr = (unsigned long)my_context->buf;
         vaddr < (unsigned long)my_context->buf + BUFFER_SIZE;
         vaddr += PAGE_SIZE)
        SetPageReserved(virt_to_page(vaddr));
    *(int *)my_context->buf = 1234;

    return 0;
}


int demo_close_rt(struct rtdm_dev_context   *context,
                  rtdm_user_info_t          *user_info)
{
    struct demodrv_context  *my_context;


    my_context = (struct demodrv_context *)context->dev_private;

    printk("%d\n", *((int *)my_context->buf + 1000));

    kfree(my_context->buf);

    return 0;
}


int demo_ioctl_rt(struct rtdm_dev_context   *context,
                  rtdm_user_info_t          *user_info,
                  int                       request,
                  void                      *arg)
{
    struct demodrv_context  *my_context;
    int err;


    my_context = (struct demodrv_context *)context->dev_private;

    printk("buf = %p:%x\n", my_context->buf, *(int *)my_context->buf);

    err = rtdm_mmap_to_user(user_info, my_context->buf, BUFFER_SIZE,
                            PROT_READ|PROT_WRITE, (void **)arg, &mmap_ops,
                            0x12345678);
    printk("rtdm_mmap = %p %d\n", *(void **)arg, err);

    return 0;
}


static struct rtdm_device demo_device = {
    struct_version:     RTDM_DEVICE_STRUCT_VER,

    device_flags:       RTDM_NAMED_DEVICE,
    context_size:       sizeof(struct demodrv_context),
    device_name:        "demodev0",

    open_rt:            NULL,
    open_nrt:           demo_open_rt,

    ops: {
        close_rt:       NULL,
        close_nrt:      demo_close_rt,

        ioctl_rt:       NULL,
        ioctl_nrt:      demo_ioctl_rt,

        read_rt:        NULL,
        read_nrt:       NULL,

        write_rt:       NULL,
        write_nrt:      NULL,

        recvmsg_rt:     NULL,
        recvmsg_nrt:    NULL,

        sendmsg_rt:     NULL,
        sendmsg_nrt:    NULL,
    },

    device_class:       RTDM_CLASS_EXPERIMENTAL,
    device_sub_class:   222,
    driver_name:        "demodrv",
    peripheral_name:    "demodev",
    provider_name:      "-",
    proc_name:          demo_device.device_name,
};

int init_module(void)
{
    int ret;


    ret = rtdm_dev_register(&demo_device);
    printk("rtdm_dev_register = %d\n", ret);

    return ret;
}


void cleanup_module(void)
{
    rtdm_dev_unregister(&demo_device, 1000);
}
_______________________________________________
Xenomai-help mailing list
[email protected]
https://mail.gna.org/listinfo/xenomai-help

Reply via email to