aboutsummaryrefslogtreecommitdiffstats
path: root/security/tf_driver/tf_device.c
diff options
context:
space:
mode:
Diffstat (limited to 'security/tf_driver/tf_device.c')
-rw-r--r--security/tf_driver/tf_device.c796
1 files changed, 796 insertions, 0 deletions
diff --git a/security/tf_driver/tf_device.c b/security/tf_driver/tf_device.c
new file mode 100644
index 00000000000..ad44b46c206
--- /dev/null
+++ b/security/tf_driver/tf_device.c
@@ -0,0 +1,796 @@
1/**
2 * Copyright (c) 2011 Trusted Logic S.A.
3 * All Rights Reserved.
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * version 2 as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
17 * MA 02111-1307 USA
18 */
19
20#include <linux/atomic.h>
21#include <linux/uaccess.h>
22#include <linux/module.h>
23#include <linux/errno.h>
24#include <linux/mm.h>
25#include <linux/page-flags.h>
26#include <linux/pm.h>
27#include <linux/syscore_ops.h>
28#include <linux/vmalloc.h>
29#include <linux/signal.h>
30#ifdef CONFIG_ANDROID
31#include <linux/device.h>
32#endif
33
34#include "tf_protocol.h"
35#include "tf_defs.h"
36#include "tf_util.h"
37#include "tf_conn.h"
38#include "tf_comm.h"
39#ifdef CONFIG_TF_ZEBRA
40#include <plat/cpu.h>
41#include "tf_zebra.h"
42#endif
43#ifdef CONFIG_TF_DRIVER_CRYPTO_FIPS
44#include "tf_crypto.h"
45#endif
46
47#include "s_version.h"
48
49/*----------------------------------------------------------------------------
50 * Forward Declarations
51 *----------------------------------------------------------------------------*/
52
53/*
54 * Creates and registers the device to be managed by the specified driver.
55 *
56 * Returns zero upon successful completion, or an appropriate error code upon
57 * failure.
58 */
59static int tf_device_register(void);
60
61
62/*
63 * Implements the device Open callback.
64 */
65static int tf_device_open(
66 struct inode *inode,
67 struct file *file);
68
69
70/*
71 * Implements the device Release callback.
72 */
73static int tf_device_release(
74 struct inode *inode,
75 struct file *file);
76
77
78/*
79 * Implements the device ioctl callback.
80 */
81static long tf_device_ioctl(
82 struct file *file,
83 unsigned int ioctl_num,
84 unsigned long ioctl_param);
85
86
87/*
88 * Implements the device shutdown callback.
89 */
90static int tf_device_shutdown(void);
91
92
93/*
94 * Implements the device suspend callback.
95 */
96static int tf_device_suspend(void);
97
98
99/*
100 * Implements the device resume callback.
101 */
102static int tf_device_resume(void);
103
104
105/*---------------------------------------------------------------------------
106 * Module Parameters
107 *---------------------------------------------------------------------------*/
108
109/*
110 * The device major number used to register a unique character device driver.
111 * Let the default value be 122
112 */
113static int device_major_number = 122;
114
115module_param(device_major_number, int, 0000);
116MODULE_PARM_DESC(device_major_number,
117 "The device major number used to register a unique character "
118 "device driver");
119
120#ifdef CONFIG_TF_TRUSTZONE
121/**
122 * The softint interrupt line used by the Secure World.
123 */
124static int soft_interrupt = -1;
125
126module_param(soft_interrupt, int, 0000);
127MODULE_PARM_DESC(soft_interrupt,
128 "The softint interrupt line used by the Secure world");
129#endif
130
131#ifdef CONFIG_TF_DRIVER_DEBUG_SUPPORT
132unsigned tf_debug_level = UINT_MAX;
133module_param_named(debug, tf_debug_level, uint, 0644);
134#endif
135
136#ifdef CONFIG_TF_DRIVER_CRYPTO_FIPS
137char *tf_integrity_hmac_sha256_expected_value;
138module_param_named(hmac_sha256, tf_integrity_hmac_sha256_expected_value,
139 charp, 0444);
140
141#ifdef CONFIG_TF_DRIVER_FAULT_INJECTION
142unsigned tf_fault_injection_mask;
143module_param_named(fault, tf_fault_injection_mask, uint, 0644);
144#endif
145
146int tf_self_test_blkcipher_align;
147module_param_named(post_align, tf_self_test_blkcipher_align, int, 0644);
148int tf_self_test_blkcipher_use_vmalloc;
149module_param_named(post_vmalloc, tf_self_test_blkcipher_use_vmalloc, int, 0644);
150#endif
151
152#ifdef CONFIG_ANDROID
153static struct class *tf_class;
154#endif
155
156/*----------------------------------------------------------------------------
157 * Global Variables
158 *----------------------------------------------------------------------------*/
159
160/*
161 * tf_driver character device definitions.
162 * read and write methods are not defined
163 * and will return an error if used by user space
164 */
165static const struct file_operations g_tf_device_file_ops = {
166 .owner = THIS_MODULE,
167 .open = tf_device_open,
168 .release = tf_device_release,
169 .unlocked_ioctl = tf_device_ioctl,
170 .llseek = no_llseek,
171};
172
173
174static struct syscore_ops g_tf_device_syscore_ops = {
175 .shutdown = tf_device_shutdown,
176 .suspend = tf_device_suspend,
177 .resume = tf_device_resume,
178};
179
180/* The single device supported by this driver */
181static struct tf_device g_tf_dev;
182
183/*----------------------------------------------------------------------------
184 * Implementations
185 *----------------------------------------------------------------------------*/
186
187struct tf_device *tf_get_device(void)
188{
189 return &g_tf_dev;
190}
191
192/*
193 * sysfs entries
194 */
195struct tf_sysfs_entry {
196 struct attribute attr;
197 ssize_t (*show)(struct tf_device *, char *);
198 ssize_t (*store)(struct tf_device *, const char *, size_t);
199};
200
201/*
202 * sysfs entry showing allocation stats
203 */
204static ssize_t info_show(struct tf_device *dev, char *buf)
205{
206 struct tf_device_stats *dev_stats = &dev->stats;
207
208 return snprintf(buf, PAGE_SIZE,
209 "stat.memories.allocated: %d\n"
210 "stat.pages.allocated: %d\n"
211 "stat.pages.locked: %d\n",
212 atomic_read(&dev_stats->stat_memories_allocated),
213 atomic_read(&dev_stats->stat_pages_allocated),
214 atomic_read(&dev_stats->stat_pages_locked));
215}
216static struct tf_sysfs_entry tf_info_entry = __ATTR_RO(info);
217
218#ifdef CONFIG_TF_ZEBRA
219/*
220 * sysfs entry showing whether secure world is up and running
221 */
222static ssize_t tf_started_show(struct tf_device *dev, char *buf)
223{
224 int tf_started = test_bit(TF_COMM_FLAG_PA_AVAILABLE,
225 &dev->sm.flags);
226
227 return snprintf(buf, PAGE_SIZE, "%s\n", tf_started ? "yes" : "no");
228}
229static struct tf_sysfs_entry tf_started_entry =
230 __ATTR_RO(tf_started);
231
232static ssize_t workspace_addr_show(struct tf_device *dev, char *buf)
233{
234 return snprintf(buf, PAGE_SIZE, "0x%08x\n", dev->workspace_addr);
235}
236static struct tf_sysfs_entry tf_workspace_addr_entry =
237 __ATTR_RO(workspace_addr);
238
239static ssize_t workspace_size_show(struct tf_device *dev, char *buf)
240{
241 return snprintf(buf, PAGE_SIZE, "0x%08x\n", dev->workspace_size);
242}
243static struct tf_sysfs_entry tf_workspace_size_entry =
244 __ATTR_RO(workspace_size);
245#endif
246
247static ssize_t tf_attr_show(struct kobject *kobj, struct attribute *attr,
248 char *page)
249{
250 struct tf_sysfs_entry *entry = container_of(attr, struct tf_sysfs_entry,
251 attr);
252 struct tf_device *dev = container_of(kobj, struct tf_device, kobj);
253
254 if (!entry->show)
255 return -EIO;
256
257 return entry->show(dev, page);
258}
259
260static ssize_t tf_attr_store(struct kobject *kobj, struct attribute *attr,
261 const char *page, size_t length)
262{
263 struct tf_sysfs_entry *entry = container_of(attr, struct tf_sysfs_entry,
264 attr);
265 struct tf_device *dev = container_of(kobj, struct tf_device, kobj);
266
267 if (!entry->store)
268 return -EIO;
269
270 return entry->store(dev, page, length);
271}
272
273static void tf_kobj_release(struct kobject *kobj) {}
274
275static struct attribute *tf_default_attrs[] = {
276 &tf_info_entry.attr,
277#ifdef CONFIG_TF_ZEBRA
278 &tf_started_entry.attr,
279 &tf_workspace_addr_entry.attr,
280 &tf_workspace_size_entry.attr,
281#endif
282 NULL,
283};
284static const struct sysfs_ops tf_sysfs_ops = {
285 .show = tf_attr_show,
286 .store = tf_attr_store,
287};
288static struct kobj_type tf_ktype = {
289 .release = tf_kobj_release,
290 .sysfs_ops = &tf_sysfs_ops,
291 .default_attrs = tf_default_attrs
292};
293
294/*----------------------------------------------------------------------------*/
295
296#if defined(MODULE) && defined(CONFIG_TF_ZEBRA)
297static char *smc_mem;
298module_param(smc_mem, charp, S_IRUGO);
299#endif
300
301/*
302 * First routine called when the kernel module is loaded
303 */
304static int __init tf_device_register(void)
305{
306 int error;
307 struct tf_device *dev = &g_tf_dev;
308
309 dprintk(KERN_INFO "tf_device_register()\n");
310
311 /*
312 * Initialize the device
313 */
314 dev->dev_number = MKDEV(device_major_number,
315 TF_DEVICE_MINOR_NUMBER);
316 cdev_init(&dev->cdev, &g_tf_device_file_ops);
317 dev->cdev.owner = THIS_MODULE;
318
319 INIT_LIST_HEAD(&dev->connection_list);
320 spin_lock_init(&dev->connection_list_lock);
321
322#if defined(MODULE) && defined(CONFIG_TF_ZEBRA)
323 error = (*tf_comm_early_init)();
324 if (error)
325 goto module_early_init_failed;
326
327 error = tf_device_mshield_init(smc_mem);
328 if (error)
329 goto mshield_init_failed;
330
331#ifdef CONFIG_TF_DRIVER_CRYPTO_FIPS
332 error = tf_crypto_hmac_module_init();
333 if (error)
334 goto hmac_init_failed;
335
336 error = tf_self_test_register_device();
337 if (error)
338 goto self_test_register_device_failed;
339#endif
340#endif
341
342 /* register the sysfs object driver stats */
343 error = kobject_init_and_add(&dev->kobj, &tf_ktype, NULL, "%s",
344 TF_DEVICE_BASE_NAME);
345 if (error) {
346 printk(KERN_ERR "tf_device_register(): "
347 "kobject_init_and_add failed (error %d)!\n", error);
348 kobject_put(&dev->kobj);
349 goto kobject_init_and_add_failed;
350 }
351
352 /*
353 * Register the system device.
354 */
355 register_syscore_ops(&g_tf_device_syscore_ops);
356
357 /*
358 * Register the char device.
359 */
360 printk(KERN_INFO "Registering char device %s (%u:%u)\n",
361 TF_DEVICE_BASE_NAME,
362 MAJOR(dev->dev_number),
363 MINOR(dev->dev_number));
364 error = register_chrdev_region(dev->dev_number, 1,
365 TF_DEVICE_BASE_NAME);
366 if (error != 0) {
367 printk(KERN_ERR "tf_device_register():"
368 " register_chrdev_region failed (error %d)!\n",
369 error);
370 goto register_chrdev_region_failed;
371 }
372
373 error = cdev_add(&dev->cdev, dev->dev_number, 1);
374 if (error != 0) {
375 printk(KERN_ERR "tf_device_register(): "
376 "cdev_add failed (error %d)!\n",
377 error);
378 goto cdev_add_failed;
379 }
380
381 /*
382 * Initialize the communication with the Secure World.
383 */
384#ifdef CONFIG_TF_TRUSTZONE
385 dev->sm.soft_int_irq = soft_interrupt;
386#endif
387 error = tf_init(&g_tf_dev.sm);
388 if (error != S_SUCCESS) {
389 dprintk(KERN_ERR "tf_device_register(): "
390 "tf_init failed (error %d)!\n",
391 error);
392 goto init_failed;
393 }
394
395#ifdef CONFIG_TF_DRIVER_CRYPTO_FIPS
396 error = tf_self_test_post_init(&(dev_stats->kobj));
397 /* N.B. error > 0 indicates a POST failure, which will not
398 prevent the module from loading. */
399 if (error < 0) {
400 dprintk(KERN_ERR "tf_device_register(): "
401 "tf_self_test_post_vectors failed (error %d)!\n",
402 error);
403 goto post_failed;
404 }
405#endif
406
407#ifdef CONFIG_ANDROID
408 tf_class = class_create(THIS_MODULE, TF_DEVICE_BASE_NAME);
409 device_create(tf_class, NULL,
410 dev->dev_number,
411 NULL, TF_DEVICE_BASE_NAME);
412#endif
413
414#ifdef CONFIG_TF_ZEBRA
415 /*
416 * Initializes the /dev/tf_ctrl device node.
417 */
418 error = tf_ctrl_device_register();
419 if (error)
420 goto ctrl_failed;
421#endif
422
423#ifdef CONFIG_TF_DRIVER_DEBUG_SUPPORT
424 address_cache_property((unsigned long) &tf_device_register);
425#endif
426 /*
427 * Successful completion.
428 */
429
430 dprintk(KERN_INFO "tf_device_register(): Success\n");
431 return 0;
432
433 /*
434 * Error: undo all operations in the reverse order
435 */
436#ifdef CONFIG_TF_ZEBRA
437ctrl_failed:
438#endif
439#ifdef CONFIG_TF_DRIVER_CRYPTO_FIPS
440 tf_self_test_post_exit();
441post_failed:
442#endif
443init_failed:
444 cdev_del(&dev->cdev);
445cdev_add_failed:
446 unregister_chrdev_region(dev->dev_number, 1);
447register_chrdev_region_failed:
448 unregister_syscore_ops(&g_tf_device_syscore_ops);
449kobject_init_and_add_failed:
450 kobject_del(&g_tf_dev.kobj);
451
452#if defined(MODULE) && defined(CONFIG_TF_ZEBRA)
453#ifdef CONFIG_TF_DRIVER_CRYPTO_FIPS
454 tf_self_test_unregister_device();
455self_test_register_device_failed:
456 tf_crypto_hmac_module_exit();
457hmac_init_failed:
458#endif
459 tf_device_mshield_exit();
460mshield_init_failed:
461module_early_init_failed:
462#endif
463 dprintk(KERN_INFO "tf_device_register(): Failure (error %d)\n",
464 error);
465 return error;
466}
467
468/*----------------------------------------------------------------------------*/
469
470static int tf_device_open(struct inode *inode, struct file *file)
471{
472 int error;
473 struct tf_device *dev = &g_tf_dev;
474 struct tf_connection *connection = NULL;
475
476 dprintk(KERN_INFO "tf_device_open(%u:%u, %p)\n",
477 imajor(inode), iminor(inode), file);
478
479 /* Dummy lseek for non-seekable driver */
480 error = nonseekable_open(inode, file);
481 if (error != 0) {
482 dprintk(KERN_ERR "tf_device_open(%p): "
483 "nonseekable_open failed (error %d)!\n",
484 file, error);
485 goto error;
486 }
487
488#ifndef CONFIG_ANDROID
489 /*
490 * Check file flags. We only autthorize the O_RDWR access
491 */
492 if (file->f_flags != O_RDWR) {
493 dprintk(KERN_ERR "tf_device_open(%p): "
494 "Invalid access mode %u\n",
495 file, file->f_flags);
496 error = -EACCES;
497 goto error;
498 }
499#endif
500
501 /*
502 * Open a new connection.
503 */
504
505 error = tf_open(dev, file, &connection);
506 if (error != 0) {
507 dprintk(KERN_ERR "tf_device_open(%p): "
508 "tf_open failed (error %d)!\n",
509 file, error);
510 goto error;
511 }
512
513 file->private_data = connection;
514
515 /*
516 * Send the CreateDeviceContext command to the secure
517 */
518 error = tf_create_device_context(connection);
519 if (error != 0) {
520 dprintk(KERN_ERR "tf_device_open(%p): "
521 "tf_create_device_context failed (error %d)!\n",
522 file, error);
523 goto error1;
524 }
525
526 /*
527 * Successful completion.
528 */
529
530 dprintk(KERN_INFO "tf_device_open(%p): Success (connection=%p)\n",
531 file, connection);
532 return 0;
533
534 /*
535 * Error handling.
536 */
537
538error1:
539 tf_close(connection);
540error:
541 dprintk(KERN_INFO "tf_device_open(%p): Failure (error %d)\n",
542 file, error);
543 return error;
544}
545
546/*----------------------------------------------------------------------------*/
547
548static int tf_device_release(struct inode *inode, struct file *file)
549{
550 struct tf_connection *connection;
551
552 dprintk(KERN_INFO "tf_device_release(%u:%u, %p)\n",
553 imajor(inode), iminor(inode), file);
554
555 connection = tf_conn_from_file(file);
556 tf_close(connection);
557
558 dprintk(KERN_INFO "tf_device_release(%p): Success\n", file);
559 return 0;
560}
561
562/*----------------------------------------------------------------------------*/
563
564static long tf_device_ioctl(struct file *file, unsigned int ioctl_num,
565 unsigned long ioctl_param)
566{
567 int result = S_SUCCESS;
568 struct tf_connection *connection;
569 union tf_command command;
570 struct tf_command_header header;
571 union tf_answer answer;
572 u32 command_size;
573 u32 answer_size;
574 void *user_answer;
575
576 dprintk(KERN_INFO "tf_device_ioctl(%p, %u, %p)\n",
577 file, ioctl_num, (void *) ioctl_param);
578
579 switch (ioctl_num) {
580 case IOCTL_TF_GET_VERSION:
581 /* ioctl is asking for the driver interface version */
582 result = TF_DRIVER_INTERFACE_VERSION;
583 goto exit;
584
585 case IOCTL_TF_EXCHANGE:
586 /*
587 * ioctl is asking to perform a message exchange with the Secure
588 * Module
589 */
590
591 /*
592 * Make a local copy of the data from the user application
593 * This routine checks the data is readable
594 *
595 * Get the header first.
596 */
597 if (copy_from_user(&header,
598 (struct tf_command_header *)ioctl_param,
599 sizeof(struct tf_command_header))) {
600 dprintk(KERN_ERR "tf_device_ioctl(%p): "
601 "Cannot access ioctl parameter %p\n",
602 file, (void *) ioctl_param);
603 result = -EFAULT;
604 goto exit;
605 }
606
607 /* size in words of u32 */
608 command_size = header.message_size +
609 sizeof(struct tf_command_header)/sizeof(u32);
610 if (command_size > sizeof(command)/sizeof(u32)) {
611 dprintk(KERN_ERR "tf_device_ioctl(%p): "
612 "Buffer overflow: too many bytes to copy %d\n",
613 file, command_size);
614 result = -EFAULT;
615 goto exit;
616 }
617
618 if (copy_from_user(&command,
619 (union tf_command *)ioctl_param,
620 command_size * sizeof(u32))) {
621 dprintk(KERN_ERR "tf_device_ioctl(%p): "
622 "Cannot access ioctl parameter %p\n",
623 file, (void *) ioctl_param);
624 result = -EFAULT;
625 goto exit;
626 }
627
628 connection = tf_conn_from_file(file);
629 BUG_ON(connection == NULL);
630
631 /*
632 * The answer memory space address is in the operation_id field
633 */
634 user_answer = (void *) command.header.operation_id;
635
636 atomic_inc(&(connection->pending_op_count));
637
638 dprintk(KERN_WARNING "tf_device_ioctl(%p): "
639 "Sending message type 0x%08x\n",
640 file, command.header.message_type);
641
642 switch (command.header.message_type) {
643 case TF_MESSAGE_TYPE_OPEN_CLIENT_SESSION:
644 result = tf_open_client_session(connection,
645 &command, &answer);
646 break;
647
648 case TF_MESSAGE_TYPE_CLOSE_CLIENT_SESSION:
649 result = tf_close_client_session(connection,
650 &command, &answer);
651 break;
652
653 case TF_MESSAGE_TYPE_REGISTER_SHARED_MEMORY:
654 result = tf_register_shared_memory(connection,
655 &command, &answer);
656 break;
657
658 case TF_MESSAGE_TYPE_RELEASE_SHARED_MEMORY:
659 result = tf_release_shared_memory(connection,
660 &command, &answer);
661 break;
662
663 case TF_MESSAGE_TYPE_INVOKE_CLIENT_COMMAND:
664 result = tf_invoke_client_command(connection,
665 &command, &answer);
666 break;
667
668 case TF_MESSAGE_TYPE_CANCEL_CLIENT_COMMAND:
669 result = tf_cancel_client_command(connection,
670 &command, &answer);
671 break;
672
673 default:
674 dprintk(KERN_ERR "tf_device_ioctl(%p): "
675 "Incorrect message type (0x%08x)!\n",
676 connection, command.header.message_type);
677 result = -EOPNOTSUPP;
678 break;
679 }
680
681 atomic_dec(&(connection->pending_op_count));
682
683 if (result != 0) {
684 dprintk(KERN_WARNING "tf_device_ioctl(%p): "
685 "Operation returning error code 0x%08x)!\n",
686 file, result);
687 goto exit;
688 }
689
690 /*
691 * Copy the answer back to the user space application.
692 * The driver does not check this field, only copy back to user
693 * space the data handed over by Secure World
694 */
695 answer_size = answer.header.message_size +
696 sizeof(struct tf_answer_header)/sizeof(u32);
697 if (copy_to_user(user_answer,
698 &answer, answer_size * sizeof(u32))) {
699 dprintk(KERN_WARNING "tf_device_ioctl(%p): "
700 "Failed to copy back the full command "
701 "answer to %p\n", file, user_answer);
702 result = -EFAULT;
703 goto exit;
704 }
705
706 /* successful completion */
707 dprintk(KERN_INFO "tf_device_ioctl(%p): Success\n", file);
708 break;
709
710 case IOCTL_TF_GET_DESCRIPTION: {
711 /* ioctl asking for the version information buffer */
712 struct tf_version_information_buffer *pInfoBuffer;
713
714 dprintk(KERN_INFO "IOCTL_TF_GET_DESCRIPTION:(%p, %u, %p)\n",
715 file, ioctl_num, (void *) ioctl_param);
716
717 pInfoBuffer =
718 ((struct tf_version_information_buffer *) ioctl_param);
719
720 dprintk(KERN_INFO "IOCTL_TF_GET_DESCRIPTION1: "
721 "driver_description=\"%64s\"\n", S_VERSION_STRING);
722
723 if (copy_to_user(pInfoBuffer->driver_description,
724 S_VERSION_STRING,
725 strlen(S_VERSION_STRING) + 1)) {
726 dprintk(KERN_ERR "tf_device_ioctl(%p): "
727 "Fail to copy back the driver description "
728 "to %p\n",
729 file, pInfoBuffer->driver_description);
730 result = -EFAULT;
731 goto exit;
732 }
733
734 dprintk(KERN_INFO "IOCTL_TF_GET_DESCRIPTION2: "
735 "secure_world_description=\"%64s\"\n",
736 tf_get_description(&g_tf_dev.sm));
737
738 if (copy_to_user(pInfoBuffer->secure_world_description,
739 tf_get_description(&g_tf_dev.sm),
740 TF_DESCRIPTION_BUFFER_LENGTH)) {
741 dprintk(KERN_WARNING "tf_device_ioctl(%p): "
742 "Failed to copy back the secure world "
743 "description to %p\n",
744 file, pInfoBuffer->secure_world_description);
745 result = -EFAULT;
746 goto exit;
747 }
748 break;
749 }
750
751 default:
752 dprintk(KERN_ERR "tf_device_ioctl(%p): "
753 "Unknown IOCTL code 0x%08x!\n",
754 file, ioctl_num);
755 result = -EOPNOTSUPP;
756 goto exit;
757 }
758
759exit:
760 return result;
761}
762
763/*----------------------------------------------------------------------------*/
764
765static int tf_device_shutdown(void)
766{
767
768 return tf_power_management(&g_tf_dev.sm,
769 TF_POWER_OPERATION_SHUTDOWN);
770}
771
772/*----------------------------------------------------------------------------*/
773
774static int tf_device_suspend(void)
775{
776 dprintk(KERN_INFO "tf_device_suspend: Enter\n");
777 return tf_power_management(&g_tf_dev.sm,
778 TF_POWER_OPERATION_HIBERNATE);
779}
780
781
782/*----------------------------------------------------------------------------*/
783
784static int tf_device_resume(void)
785{
786 return tf_power_management(&g_tf_dev.sm,
787 TF_POWER_OPERATION_RESUME);
788}
789
790
791/*----------------------------------------------------------------------------*/
792
793module_init(tf_device_register);
794
795MODULE_LICENSE("GPL");
796MODULE_AUTHOR("Trusted Logic S.A.");