Initial commit
[kernel/linux-3.0.git] / drivers / gpu / vithar / ump / src / devicedrv / linux / ump_kernel_linux.c
1 /*
2  *
3  * (C) COPYRIGHT 2008-2012 ARM Limited. All rights reserved.
4  *
5  * This program is free software and is provided to you under the terms of the GNU General Public License version 2
6  * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
7  * 
8  * A copy of the licence is included with the program, and can also be obtained from Free Software
9  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
10  * 
11  */
12
13
14
15 #if UMP_LICENSE_IS_GPL
16 #define UMP_KERNEL_LINUX_LICENSE "GPL"
17 #else
18 #define UMP_KERNEL_LINUX_LICENSE "Proprietary"
19 #endif
20
21 #include <ump/src/ump_ioctl.h>
22 #include <ump/ump_kernel_interface.h>
23
24 #include <asm/uaccess.h>                 /* copy_*_user */
25 #include <linux/module.h>            /* kernel module definitions */
26 #include <linux/fs.h>                /* file system operations */
27 #include <linux/cdev.h>              /* character device definitions */
28 #include <linux/ioport.h>            /* request_mem_region */
29
30 #if UMP_LICENSE_IS_GPL
31 #include <linux/device.h>            /* class registration support */
32 #endif
33
34 #include <common/ump_kernel_core.h>
35
36 #include "ump_kernel_linux_mem.h"
37 #include <ump_arch.h>
38
39
40 struct ump_linux_device
41 {
42         struct cdev cdev;
43 #if UMP_LICENSE_IS_GPL
44         struct class * ump_class;
45 #endif
46 };
47
48 /* Name of the UMP device driver */
49 static char ump_dev_name[] = "ump"; /* should be const, but the functions we call requires non-cost */
50
51 /* Module parameter to control log level */
52 int ump_debug_level = 2;
53 module_param(ump_debug_level, int, S_IRUSR | S_IWUSR | S_IWGRP | S_IRGRP | S_IROTH); /* rw-rw-r-- */
54 MODULE_PARM_DESC(ump_debug_level, "Higher number, more dmesg output");
55
56 /* By default the module uses any available major, but it's possible to set it at load time to a specific number */
57 int ump_major = 0;
58 module_param(ump_major, int, S_IRUGO); /* r--r--r-- */
59 MODULE_PARM_DESC(ump_major, "Device major number");
60
61 char * ump_revision = UMP_SVN_REV_STRING;
62 module_param(ump_revision, charp, S_IRUGO); /* r--r--r-- */
63 MODULE_PARM_DESC(ump_revision, "Revision info");
64
65 static int umpp_linux_open(struct inode *inode, struct file *filp);
66 static int umpp_linux_release(struct inode *inode, struct file *filp);
67 #ifdef HAVE_UNLOCKED_IOCTL
68 static long umpp_linux_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
69 #else
70 static int umpp_linux_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg);
71 #endif
72
73 /* This variable defines the file operations this UMP device driver offers */
74 static struct file_operations ump_fops =
75 {
76         .owner   = THIS_MODULE,
77         .open    = umpp_linux_open,
78         .release = umpp_linux_release,
79 #ifdef HAVE_UNLOCKED_IOCTL
80         .unlocked_ioctl   = umpp_linux_ioctl,
81 #else
82         .ioctl   = umpp_linux_ioctl,
83 #endif
84         .compat_ioctl = umpp_linux_ioctl,
85         .mmap = umpp_linux_mmap
86 };
87
88 /* import module handling */
89 DEFINE_MUTEX(import_list_lock);
90 struct ump_import_handler *  import_handlers[UMPP_EXTERNAL_MEM_COUNT];
91
92 /* The global variable containing the global device data */
93 static struct ump_linux_device ump_linux_device;
94
95 #define DBG_MSG(level, ...) do { \
96 if ((level) <=  ump_debug_level)\
97 {\
98 printk(KERN_DEBUG "UMP<" #level ">:\n" __VA_ARGS__);\
99 } \
100 } while (0)
101
102 #define MSG_ERR(...) do{ \
103 printk(KERN_ERR "UMP: ERR: %s\n           %s()%4d\n", __FILE__, __func__  , __LINE__) ; \
104 printk(KERN_ERR __VA_ARGS__); \
105 printk(KERN_ERR "\n"); \
106 } while(0)
107
108 #define MSG(...) do{ \
109 printk(KERN_INFO "UMP: " __VA_ARGS__);\
110 } while (0)
111
112 /*
113  * This function is called by Linux to initialize this module.
114  * All we do is initialize the UMP device driver.
115  */
116 static int __init umpp_linux_initialize_module(void)
117 {
118         ump_result err;
119
120         DBG_MSG(2, "Inserting UMP device driver. Compiled: %s, time: %s\n", __DATE__, __TIME__);
121
122         err = umpp_core_constructor();
123         if (UMP_OK != err)
124         {
125                 MSG_ERR("UMP device driver init failed\n");
126                 return -ENOTTY;
127         }
128
129         MSG("UMP device driver %s loaded\n", UMP_SVN_REV_STRING);
130
131         return 0;
132 }
133
134
135
136 /*
137  * This function is called by Linux to unload/terminate/exit/cleanup this module.
138  * All we do is terminate the UMP device driver.
139  */
140 static void __exit umpp_linux_cleanup_module(void)
141 {
142         DBG_MSG(2, "Unloading UMP device driver\n");
143         umpp_core_destructor();
144         DBG_MSG(2, "Module unloaded\n");
145 }
146
147
148
149 /*
150  * Initialize the UMP device driver.
151  */
152 ump_result umpp_device_initialize(void)
153 {
154         int err;
155         dev_t dev = 0;
156
157         if (0 == ump_major)
158         {
159                 /* auto select a major */
160                 err = alloc_chrdev_region(&dev, 0, 1, ump_dev_name);
161                 ump_major = MAJOR(dev);
162         }
163         else
164         {
165                 /* use load time defined major number */
166                 dev = MKDEV(ump_major, 0);
167                 err = register_chrdev_region(dev, 1, ump_dev_name);
168         }
169
170         if (0 == err)
171         {
172                 memset(&ump_linux_device, 0, sizeof(ump_linux_device));
173
174                 /* initialize our char dev data */
175                 cdev_init(&ump_linux_device.cdev, &ump_fops);
176                 ump_linux_device.cdev.owner = THIS_MODULE;
177                 ump_linux_device.cdev.ops = &ump_fops;
178
179                 /* register char dev with the kernel */
180                 err = cdev_add(&ump_linux_device.cdev, dev, 1/*count*/);
181                 if (0 == err)
182                 {
183
184 #if UMP_LICENSE_IS_GPL
185                         ump_linux_device.ump_class = class_create(THIS_MODULE, ump_dev_name);
186                         if (IS_ERR(ump_linux_device.ump_class))
187                         {
188                                 err = PTR_ERR(ump_linux_device.ump_class);
189                         }
190                         else
191                         {
192                                 struct device * mdev;
193                                 mdev = device_create(ump_linux_device.ump_class, NULL, dev, NULL, ump_dev_name);
194                                 if (!IS_ERR(mdev))
195                                 {
196                                         return UMP_OK;
197                                 }
198
199                                 err = PTR_ERR(mdev);
200                                 class_destroy(ump_linux_device.ump_class);
201                         }
202                         cdev_del(&ump_linux_device.cdev);
203 #else
204                         return UMP_OK;
205 #endif
206                 }
207
208                 unregister_chrdev_region(dev, 1);
209         }
210
211         return UMP_ERROR;
212 }
213
214
215
216 /*
217  * Terminate the UMP device driver
218  */
219 void umpp_device_terminate(void)
220 {
221         dev_t dev = MKDEV(ump_major, 0);
222
223 #if UMP_LICENSE_IS_GPL
224         device_destroy(ump_linux_device.ump_class, dev);
225         class_destroy(ump_linux_device.ump_class);
226 #endif
227
228         /* unregister char device */
229         cdev_del(&ump_linux_device.cdev);
230
231         /* free major */
232         unregister_chrdev_region(dev, 1);
233 }
234
235
236 static int umpp_linux_open(struct inode *inode, struct file *filp)
237 {
238         umpp_session *session;
239         
240         session = umpp_core_session_start();
241         if (NULL == session) 
242         {
243                 return -EFAULT;
244         }
245         
246         filp->private_data = session;
247
248         return 0;
249 }
250
251 static int umpp_linux_release(struct inode *inode, struct file *filp)
252 {
253         umpp_session *session;
254         
255         session = filp->private_data;
256
257         umpp_core_session_end(session);
258
259         filp->private_data = NULL;
260
261         return 0;
262 }
263
264 /**************************/
265 /*ioctl specific functions*/
266 /**************************/
267 static int do_ump_dd_allocate(umpp_session * session, ump_k_allocate * params)
268 {
269         ump_dd_handle new_allocation;
270         new_allocation = ump_dd_allocate_64(params->size, params->alloc_flags, NULL, NULL, NULL);
271
272         if (UMP_DD_INVALID_MEMORY_HANDLE != new_allocation)
273         {
274                 umpp_session_memory_usage * tracker;
275
276                 tracker = kmalloc(sizeof(*tracker), GFP_KERNEL | __GFP_HARDWALL);
277                 if (NULL != tracker)
278                 {
279                         /* update the return struct with the new ID */
280                         params->secure_id = ump_dd_secure_id_get(new_allocation);
281
282                         tracker->mem = new_allocation;
283                         tracker->id = params->secure_id;
284                         atomic_set(&tracker->process_usage_count, 1);
285
286                         /* link it into the session in-use list */
287                         mutex_lock(&session->session_lock);
288                         list_add(&tracker->link, &session->memory_usage);
289                         mutex_unlock(&session->session_lock);
290
291                         return 0;
292                 }
293                 ump_dd_release(new_allocation);
294         }
295
296         printk(KERN_WARNING "UMP: Allocation FAILED\n");
297         return -ENOMEM;
298 }
299
300 static int do_ump_dd_retain(umpp_session * session, ump_k_retain * params)
301 {
302         umpp_session_memory_usage * it;
303
304         mutex_lock(&session->session_lock);
305
306         /* try to find it on the session usage list */
307         list_for_each_entry(it, &session->memory_usage, link)
308         {
309                 if (it->id == params->secure_id)
310                 {
311                         /* found to already be in use */
312                         /* check for overflow */
313                         while(1)
314                         {
315                                 int refcnt = atomic_read(&it->process_usage_count);
316                                 if (refcnt + 1 > 0)
317                                 {
318                                         /* add a process local ref */
319                                         if(atomic_cmpxchg(&it->process_usage_count, refcnt, refcnt + 1) == refcnt)
320                                         {
321                                                 mutex_unlock(&session->session_lock);
322                                                 return 0;
323                                         }
324                                 }
325                                 else
326                                 {
327                                         /* maximum usage cap reached */
328                                         mutex_unlock(&session->session_lock);
329                                         return -EBUSY;
330                                 }
331                         }
332                 }
333         }
334         /* try to look it up globally */
335
336         it = kmalloc(sizeof(*it), GFP_KERNEL);
337
338         if (NULL != it)
339         {
340                 it->mem = ump_dd_from_secure_id(params->secure_id);
341                 if (UMP_DD_INVALID_MEMORY_HANDLE != it->mem)
342                 {
343                         /* found, add it to the session usage list */
344                         it->id = params->secure_id;
345                         atomic_set(&it->process_usage_count, 1);
346                         list_add(&it->link, &session->memory_usage);
347                 }
348                 else
349                 {
350                         /* not found */
351                         kfree(it);
352                         it = NULL;
353                 }
354         }
355
356         mutex_unlock(&session->session_lock);
357
358         return (NULL != it) ? 0 : -ENODEV;
359 }
360
361
362 static int do_ump_dd_release(umpp_session * session, ump_k_release * params)
363 {
364         umpp_session_memory_usage * it;
365         int result = -ENODEV;
366
367         mutex_lock(&session->session_lock);
368
369         /* only do a release if found on the session list */
370         list_for_each_entry(it, &session->memory_usage, link)
371         {
372                 if (it->id == params->secure_id)
373                 {
374                         /* found, a valid call */
375                         result = 0;
376
377                         if (0 == atomic_sub_return(1, &it->process_usage_count))
378                         {
379                                 /* last ref in this process remove from the usage list and remove the underlying ref */
380                                 list_del(&it->link);
381                                 ump_dd_release(it->mem);
382                                 kfree(it);
383                         }
384
385                         break;
386                 }
387         }
388         mutex_unlock(&session->session_lock);
389
390         return result;
391 }
392
393 static int do_ump_dd_sizequery(umpp_session * session, ump_k_sizequery * params)
394 {
395         umpp_session_memory_usage * it;
396         int result = -ENODEV;
397
398         mutex_lock(&session->session_lock);
399
400         /* only valid if found on the session list */
401         list_for_each_entry(it, &session->memory_usage, link)
402         {
403                 if (it->id == params->secure_id)
404                 {
405                         /* found, a valid call */
406                         params->size = ump_dd_size_get_64(it->mem);
407                         result = 0;
408                         break;
409                 }
410
411         }
412         mutex_unlock(&session->session_lock);
413
414         return result;
415 }
416
417 static int do_ump_dd_allocation_flags_get(umpp_session * session, ump_k_allocation_flags * params)
418 {
419         umpp_session_memory_usage * it;
420         int result = -ENODEV;
421
422         mutex_lock(&session->session_lock);
423
424         /* only valid if found on the session list */
425         list_for_each_entry(it, &session->memory_usage, link)
426         {
427                 if (it->id == params->secure_id)
428                 {
429                         /* found, a valid call */
430                         params->alloc_flags = ump_dd_allocation_flags_get(it->mem);
431                         result = 0;
432                         break;
433                 }
434
435         }
436         mutex_unlock(&session->session_lock);
437
438         return result;
439 }
440
441 static int do_ump_dd_msync_now(umpp_session * session, ump_k_msync * params)
442 {
443         umpp_session_memory_usage * it;
444         int result = -ENODEV;
445
446         mutex_lock(&session->session_lock);
447
448         /* only valid if found on the session list */
449         list_for_each_entry(it, &session->memory_usage, link)
450         {
451                 if (it->id == params->secure_id)
452                 {
453                         /* found, do the cache op */
454 #if defined CONFIG_64BIT && CONFIG_64BIT
455                         if (is_compat_task())
456                         {
457                                 umpp_dd_cpu_msync_now(it->mem, params->cache_operation, params->mapped_ptr.compat_value, params->size);
458                                 result = 0;
459                         }
460                         else
461                         {
462 #endif
463                                 umpp_dd_cpu_msync_now(it->mem, params->cache_operation, params->mapped_ptr.value, params->size);
464                                 result = 0;
465 #if defined CONFIG_64BIT && CONFIG_64BIT
466                         }
467 #endif
468                         break;
469                 }
470         }
471         mutex_unlock(&session->session_lock);
472
473         return result;
474 }
475
476
477 void umpp_import_handlers_init(umpp_session * session)
478 {
479         int i;
480         mutex_lock(&import_list_lock);
481         for ( i = 1; i < UMPP_EXTERNAL_MEM_COUNT; i++ )
482         {
483                 if (import_handlers[i])
484                 {
485                         import_handlers[i]->session_begin(&session->import_handler_data[i]);
486                         /* It is OK if session_begin returned an error.
487                          * We won't do any import calls if so */
488                 }
489         }
490         mutex_unlock(&import_list_lock);
491 }
492
493 void umpp_import_handlers_term(umpp_session * session)
494 {
495         int i;
496         mutex_lock(&import_list_lock);
497         for ( i = 1; i < UMPP_EXTERNAL_MEM_COUNT; i++ )
498         {
499                 /* only call if session_begin succeeded */
500                 if (session->import_handler_data[i] != NULL)
501                 {
502                         /* if session_beging succeeded the handler
503                          * should not have unregistered with us */
504                         BUG_ON(!import_handlers[i]);
505                         import_handlers[i]->session_end(session->import_handler_data[i]);
506                         session->import_handler_data[i] = NULL;
507                 }
508         }
509         mutex_unlock(&import_list_lock);
510 }
511
512 int ump_import_module_register(enum ump_external_memory_type type, struct ump_import_handler * handler)
513 {
514         int res = -EEXIST;
515
516         /* validate input */
517         BUG_ON(type == 0 || type >= UMPP_EXTERNAL_MEM_COUNT);
518         BUG_ON(!handler);
519 #ifndef CONFIG_VITHAR
520         BUG_ON(!handler->linux_module);
521 #endif
522         BUG_ON(!handler->session_begin);
523         BUG_ON(!handler->session_end);
524         BUG_ON(!handler->import);
525
526         mutex_lock(&import_list_lock);
527
528         if (!import_handlers[type])
529         {
530                 import_handlers[type] = handler;
531                 res = 0;
532         }
533
534         mutex_unlock(&import_list_lock);
535
536         return res;
537 }
538
539 void ump_import_module_unregister(enum ump_external_memory_type type)
540 {
541         BUG_ON(type == 0 || type >= UMPP_EXTERNAL_MEM_COUNT);
542
543         mutex_lock(&import_list_lock);
544         /* an error to call this if ump_import_module_register didn't succeed */
545         BUG_ON(!import_handlers[type]);
546         import_handlers[type] = NULL;
547         mutex_unlock(&import_list_lock);
548 }
549
550 static struct ump_import_handler * import_handler_get(int type_id)
551 {
552         enum ump_external_memory_type type;
553         struct ump_import_handler * handler;
554
555         /* validate and convert input */
556         /* handle bad data here, not just BUG_ON */
557         if (type_id == 0 || type_id >= UMPP_EXTERNAL_MEM_COUNT)
558                 return NULL;
559
560         type = (enum ump_external_memory_type)type_id;
561
562         /* find the handler */
563         mutex_lock(&import_list_lock);
564
565         handler = import_handlers[type];
566
567         if (handler)
568         {
569                 if (!try_module_get(handler->linux_module))
570                 {
571                         handler = NULL;
572                 }
573         }
574
575         mutex_unlock(&import_list_lock);
576
577         return handler;
578 }
579
580 static void import_handler_put(struct ump_import_handler * handler)
581 {
582         module_put(handler->linux_module);
583 }
584
585 static int do_ump_dd_import(umpp_session * session, ump_k_import * params)
586 {
587         ump_dd_handle new_allocation = UMP_DD_INVALID_MEMORY_HANDLE;
588         struct ump_import_handler * handler;
589
590         handler = import_handler_get(params->type);
591
592         if (handler)
593         {
594                 /* try late binding if not already bound */
595                 if (!session->import_handler_data[params->type])
596                 {
597                         handler->session_begin(&session->import_handler_data[params->type]);
598                 }
599
600                 /* do we have a bound session? */
601                 if (session->import_handler_data[params->type])
602                 {
603                         new_allocation = handler->import( session->import_handler_data[params->type],
604                                                       params->phandle.value,
605                                                       params->alloc_flags);
606                 }
607
608                 /* done with the handler */
609                 import_handler_put(handler);
610         }
611
612         /* did the import succeed? */
613         if (UMP_DD_INVALID_MEMORY_HANDLE != new_allocation)
614         {
615                 umpp_session_memory_usage * tracker;
616
617                 tracker = kmalloc(sizeof(*tracker), GFP_KERNEL | __GFP_HARDWALL);
618                 if (NULL != tracker)
619                 {
620                         /* update the return struct with the new ID */
621                         params->secure_id = ump_dd_secure_id_get(new_allocation);
622
623                         tracker->mem = new_allocation;
624                         tracker->id = params->secure_id;
625                         atomic_set(&tracker->process_usage_count, 1);
626
627                         /* link it into the session in-use list */
628                         mutex_lock(&session->session_lock);
629                         list_add(&tracker->link, &session->memory_usage);
630                         mutex_unlock(&session->session_lock);
631
632                         return 0;
633                 }
634                 ump_dd_release(new_allocation);
635         }
636
637         return -ENOMEM;
638
639 }
640
641 #ifdef HAVE_UNLOCKED_IOCTL
642 static long umpp_linux_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
643 #else
644 static int umpp_linux_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
645 #endif
646 {
647         int ret;
648         uint64_t msg[(UMP_CALL_MAX_SIZE+7)>>3]; /* alignment fixup */
649         uint32_t size = _IOC_SIZE(cmd);
650         struct umpp_session *session = filp->private_data;
651
652 #ifndef HAVE_UNLOCKED_IOCTL
653         (void)inode; /* unused arg */
654 #endif
655
656         /*
657          * extract the type and number bitfields, and don't decode
658          * wrong cmds: return ENOTTY (inappropriate ioctl) before access_ok()
659          */
660         if (_IOC_TYPE(cmd) != UMP_IOC_MAGIC)
661         {
662                 return -ENOTTY;
663
664         }
665         if (_IOC_NR(cmd) > UMP_IOC_MAXNR)
666         {
667                 return -ENOTTY;
668         }
669
670         switch(cmd)
671         {
672                 case UMP_FUNC_ALLOCATE:
673                         if (size != sizeof(ump_k_allocate))
674                         {
675                                 return -ENOTTY;
676                         }
677                         if (copy_from_user(&msg, (void __user *)arg, size))
678                         {
679                                 return -EFAULT;
680                         }
681                         ret = do_ump_dd_allocate(session, (ump_k_allocate *)&msg);
682                         if (ret)
683                         {
684                                 return ret;
685                         }
686                         if (copy_to_user((void *)arg, &msg, size))
687                         {
688                                 return -EFAULT;
689                         }
690                         return 0;
691                 case UMP_FUNC_SIZEQUERY:
692                         if (size != sizeof(ump_k_sizequery))
693                         {
694                                 return -ENOTTY;
695                         }
696                         if (copy_from_user(&msg, (void __user *)arg, size))
697                         {
698                                 return -EFAULT;
699                         }
700                         ret = do_ump_dd_sizequery(session,(ump_k_sizequery*) &msg);
701                         if (ret)
702                         {
703                                 return ret;
704                         }
705                         if (copy_to_user((void *)arg, &msg, size))
706                         {
707                                 return -EFAULT;
708                         }
709                         return 0;
710                 case UMP_FUNC_MSYNC:
711                         if (size != sizeof(ump_k_msync))
712                         {
713                                 return -ENOTTY;
714                         }
715                         if (copy_from_user(&msg, (void __user *)arg, size))
716                         {
717                                 return -EFAULT;
718                         }
719                         ret = do_ump_dd_msync_now(session,(ump_k_msync*) &msg);
720                         if (ret)
721                         {
722                                 return ret;
723                         }
724                         if (copy_to_user((void *)arg, &msg, size))
725                         {
726                                 return -EFAULT;
727                         }
728                         return 0;
729                 case UMP_FUNC_IMPORT:
730                         if (size != sizeof(ump_k_import))
731                         {
732                                 return -ENOTTY;
733                         }
734                         if (copy_from_user(&msg, (void __user*)arg, size))
735                         {
736                                 return -EFAULT;
737                         }
738                         ret = do_ump_dd_import(session, (ump_k_import*) &msg);
739                         if (ret)
740                         {
741                                 return ret;
742                         }
743                         if (copy_to_user((void *)arg, &msg, size))
744                         {
745                                 return -EFAULT;
746                         }
747                         return 0;
748                 /* used only by v1 API */
749                 case UMP_FUNC_ALLOCATION_FLAGS_GET:
750                         if (size != sizeof(ump_k_allocation_flags))
751                         {
752                                 return -ENOTTY;
753                         }
754                         if (copy_from_user(&msg, (void __user *)arg, size))
755                         {
756                                 return -EFAULT;
757                         }
758                         ret = do_ump_dd_allocation_flags_get(session,(ump_k_allocation_flags*) &msg);
759                         if (ret)
760                         {
761                                 return ret;
762                         }
763                         if (copy_to_user((void *)arg, &msg, size))
764                         {
765                                 return -EFAULT;
766                         }
767                         return 0;
768                 case UMP_FUNC_RETAIN:
769                         if (size != sizeof(ump_k_retain))
770                         {
771                                 return -ENOTTY;
772                         }
773                         if (copy_from_user(&msg, (void __user *)arg, size))
774                         {
775                                 return -EFAULT;
776                         }
777                         ret = do_ump_dd_retain(session,(ump_k_retain*) &msg);
778                         if (ret)
779                         {
780                                 return ret;
781                         }
782                         return 0;
783                 case UMP_FUNC_RELEASE:
784                         if (size != sizeof(ump_k_release))
785                         {
786                                 return -ENOTTY;
787                         }
788                         if (copy_from_user(&msg, (void __user *)arg, size))
789                         {
790                                 return -EFAULT;
791                         }
792                         ret = do_ump_dd_release(session,(ump_k_release*) &msg);
793                         if (ret)
794                         {
795                                 return ret;
796                         }
797                         return 0;
798                 default:
799                         /* not ours */
800                         return -ENOTTY;
801         }
802         /*redundant below*/
803         return -ENOTTY;
804 }
805
806
807 /* Export UMP kernel space API functions */
808 EXPORT_SYMBOL(ump_dd_allocate_64);
809 EXPORT_SYMBOL(ump_dd_allocation_flags_get);
810 EXPORT_SYMBOL(ump_dd_secure_id_get);
811 EXPORT_SYMBOL(ump_dd_from_secure_id);
812 EXPORT_SYMBOL(ump_dd_phys_blocks_get_64);
813 EXPORT_SYMBOL(ump_dd_size_get_64);
814 EXPORT_SYMBOL(ump_dd_retain);
815 EXPORT_SYMBOL(ump_dd_release);
816 EXPORT_SYMBOL(ump_dd_create_from_phys_blocks_64);
817 #ifdef CONFIG_KDS
818 EXPORT_SYMBOL(ump_dd_kds_resource_get);
819 #endif
820
821 /* import API */
822 EXPORT_SYMBOL(ump_import_module_register);
823 EXPORT_SYMBOL(ump_import_module_unregister);
824
825
826
827 /* V1 API */
828 EXPORT_SYMBOL(ump_dd_handle_create_from_secure_id);
829 EXPORT_SYMBOL(ump_dd_phys_block_count_get);
830 EXPORT_SYMBOL(ump_dd_phys_block_get);
831 EXPORT_SYMBOL(ump_dd_phys_blocks_get);
832 EXPORT_SYMBOL(ump_dd_size_get);
833 EXPORT_SYMBOL(ump_dd_reference_add);
834 EXPORT_SYMBOL(ump_dd_reference_release);
835 EXPORT_SYMBOL(ump_dd_handle_create_from_phys_blocks);
836
837
838 /* Setup init and exit functions for this module */
839 module_init(umpp_linux_initialize_module);
840 module_exit(umpp_linux_cleanup_module);
841
842 /* And some module informatio */
843 MODULE_LICENSE(UMP_KERNEL_LINUX_LICENSE);
844 MODULE_AUTHOR("ARM Ltd.");
845 MODULE_VERSION(UMP_SVN_REV_STRING);