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