diff options
Diffstat (limited to 'security/tf_driver/tf_device.c')
-rw-r--r-- | security/tf_driver/tf_device.c | 873 |
1 files changed, 0 insertions, 873 deletions
diff --git a/security/tf_driver/tf_device.c b/security/tf_driver/tf_device.c deleted file mode 100644 index 9db0a41a6fde..000000000000 --- a/security/tf_driver/tf_device.c +++ /dev/null @@ -1,873 +0,0 @@ -/** - * Copyright (c) 2011 Trusted Logic S.A. - * All Rights Reserved. - * - * Copyright (C) 2011-2012 NVIDIA Corporation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - */ - -#include <linux/atomic.h> -#include <linux/uaccess.h> -#include <linux/module.h> -#include <linux/errno.h> -#include <linux/mm.h> -#include <linux/page-flags.h> -#include <linux/pm.h> -#include <linux/syscore_ops.h> -#include <linux/vmalloc.h> -#include <linux/signal.h> -#ifdef CONFIG_ANDROID -#include <linux/device.h> -#endif - -#include <trace/events/nvsecurity.h> - -#include "tf_protocol.h" -#include "tf_defs.h" -#include "tf_util.h" -#include "tf_conn.h" -#include "tf_comm.h" -#ifdef CONFIG_TF_ZEBRA -#include <plat/cpu.h> -#include "tf_zebra.h" -#endif -#ifdef CONFIG_TF_DRIVER_CRYPTO_FIPS -#include "tf_crypto.h" -#endif - -#include "s_version.h" - -/*---------------------------------------------------------------------------- - * Forward Declarations - *----------------------------------------------------------------------------*/ - -/* - * Creates and registers the device to be managed by the specified driver. - * - * Returns zero upon successful completion, or an appropriate error code upon - * failure. - */ -static int tf_device_register(void); - - -/* - * Implements the device Open callback. - */ -static int tf_device_open( - struct inode *inode, - struct file *file); - - -/* - * Implements the device Release callback. - */ -static int tf_device_release( - struct inode *inode, - struct file *file); - - -/* - * Implements the device ioctl callback. - */ -static long tf_device_ioctl( - struct file *file, - unsigned int ioctl_num, - unsigned long ioctl_param); - - -/* - * Implements the device shutdown callback. - */ -static void tf_device_shutdown(void); - - -/* - * Implements the device suspend callback. - */ -static int tf_device_suspend(void); - - -/* - * Implements the device resume callback. - */ -static void tf_device_resume(void); - - -/*--------------------------------------------------------------------------- - * Module Parameters - *---------------------------------------------------------------------------*/ - -/* - * The device major number used to register a unique character device driver. - * Let the default value be 122 - */ -static int device_major_number = 122; - -module_param(device_major_number, int, 0000); -MODULE_PARM_DESC(device_major_number, - "The device major number used to register a unique character " - "device driver"); - -#ifdef CONFIG_TF_TRUSTZONE -/** - * The softint interrupt line used by the Secure World. - */ -static int soft_interrupt = -1; - -module_param(soft_interrupt, int, 0000); -MODULE_PARM_DESC(soft_interrupt, - "The softint interrupt line used by the Secure world"); -#endif - -#ifdef CONFIG_TF_DRIVER_DEBUG_SUPPORT -unsigned tf_debug_level = UINT_MAX; -module_param_named(debug, tf_debug_level, uint, 0644); -#endif - -#ifdef CONFIG_TF_DRIVER_CRYPTO_FIPS -char *tf_integrity_hmac_sha256_expected_value; -module_param_named(hmac_sha256, tf_integrity_hmac_sha256_expected_value, - charp, 0444); - -#ifdef CONFIG_TF_DRIVER_FAULT_INJECTION -unsigned tf_fault_injection_mask; -module_param_named(fault, tf_fault_injection_mask, uint, 0644); -#endif - -int tf_self_test_blkcipher_align; -module_param_named(post_align, tf_self_test_blkcipher_align, int, 0644); -int tf_self_test_blkcipher_use_vmalloc; -module_param_named(post_vmalloc, tf_self_test_blkcipher_use_vmalloc, int, 0644); -#endif - -#ifdef CONFIG_ANDROID -static struct class *tf_class; -#endif - -/*---------------------------------------------------------------------------- - * Global Variables - *----------------------------------------------------------------------------*/ - -/* - * tf_driver character device definitions. - * read and write methods are not defined - * and will return an error if used by user space - */ -static const struct file_operations g_tf_device_file_ops = { - .owner = THIS_MODULE, - .open = tf_device_open, - .release = tf_device_release, - .unlocked_ioctl = tf_device_ioctl, - .llseek = no_llseek, -}; - - -static struct syscore_ops g_tf_device_syscore_ops = { - .shutdown = tf_device_shutdown, - .suspend = tf_device_suspend, - .resume = tf_device_resume, -}; - -/* The single device supported by this driver */ -static struct tf_device g_tf_dev; - -/*---------------------------------------------------------------------------- - * Implementations - *----------------------------------------------------------------------------*/ - -struct tf_device *tf_get_device(void) -{ - return &g_tf_dev; -} - -/* - * sysfs entries - */ -struct tf_sysfs_entry { - struct attribute attr; - ssize_t (*show)(struct tf_device *, char *); - ssize_t (*store)(struct tf_device *, const char *, size_t); -}; - -/* - * sysfs entry showing allocation stats - */ -static ssize_t info_show(struct tf_device *dev, char *buf) -{ - struct tf_device_stats *dev_stats = &dev->stats; - - return snprintf(buf, PAGE_SIZE, - "stat.memories.allocated: %d\n" - "stat.pages.allocated: %d\n" - "stat.pages.locked: %d\n", - atomic_read(&dev_stats->stat_memories_allocated), - atomic_read(&dev_stats->stat_pages_allocated), - atomic_read(&dev_stats->stat_pages_locked)); -} -static struct tf_sysfs_entry tf_info_entry = __ATTR_RO(info); - -#ifdef CONFIG_TF_ZEBRA -/* - * sysfs entry showing whether secure world is up and running - */ -static ssize_t tf_started_show(struct tf_device *dev, char *buf) -{ - int tf_started = test_bit(TF_COMM_FLAG_PA_AVAILABLE, - &dev->sm.flags); - - return snprintf(buf, PAGE_SIZE, "%s\n", tf_started ? "yes" : "no"); -} -static struct tf_sysfs_entry tf_started_entry = - __ATTR_RO(tf_started); - -static ssize_t workspace_addr_show(struct tf_device *dev, char *buf) -{ - return snprintf(buf, PAGE_SIZE, "0x%08x\n", dev->workspace_addr); -} -static struct tf_sysfs_entry tf_workspace_addr_entry = - __ATTR_RO(workspace_addr); - -static ssize_t workspace_size_show(struct tf_device *dev, char *buf) -{ - return snprintf(buf, PAGE_SIZE, "0x%08x\n", dev->workspace_size); -} -static struct tf_sysfs_entry tf_workspace_size_entry = - __ATTR_RO(workspace_size); -#endif - -static ssize_t tf_attr_show(struct kobject *kobj, struct attribute *attr, - char *page) -{ - struct tf_sysfs_entry *entry = container_of(attr, struct tf_sysfs_entry, - attr); - struct tf_device *dev = container_of(kobj, struct tf_device, kobj); - - if (!entry->show) - return -EIO; - - return entry->show(dev, page); -} - -static ssize_t tf_attr_store(struct kobject *kobj, struct attribute *attr, - const char *page, size_t length) -{ - struct tf_sysfs_entry *entry = container_of(attr, struct tf_sysfs_entry, - attr); - struct tf_device *dev = container_of(kobj, struct tf_device, kobj); - - if (!entry->store) - return -EIO; - - return entry->store(dev, page, length); -} - -static void tf_kobj_release(struct kobject *kobj) {} - -static struct attribute *tf_default_attrs[] = { - &tf_info_entry.attr, -#ifdef CONFIG_TF_ZEBRA - &tf_started_entry.attr, - &tf_workspace_addr_entry.attr, - &tf_workspace_size_entry.attr, -#endif - NULL, -}; -static const struct sysfs_ops tf_sysfs_ops = { - .show = tf_attr_show, - .store = tf_attr_store, -}; -static struct kobj_type tf_ktype = { - .release = tf_kobj_release, - .sysfs_ops = &tf_sysfs_ops, - .default_attrs = tf_default_attrs -}; - -/*----------------------------------------------------------------------------*/ - -#if defined(MODULE) && defined(CONFIG_TF_ZEBRA) -static char *smc_mem; -module_param(smc_mem, charp, S_IRUGO); -#endif - -/* - * First routine called when the kernel module is loaded - */ -static int __init tf_device_register(void) -{ - int error; - struct tf_device *dev = &g_tf_dev; - - dprintk(KERN_INFO "tf_device_register()\n"); - - /* - * Initialize the device - */ - dev->dev_number = MKDEV(device_major_number, - TF_DEVICE_MINOR_NUMBER); - cdev_init(&dev->cdev, &g_tf_device_file_ops); - dev->cdev.owner = THIS_MODULE; - - INIT_LIST_HEAD(&dev->connection_list); - spin_lock_init(&dev->connection_list_lock); - -#if defined(MODULE) && defined(CONFIG_TF_ZEBRA) - error = (*tf_comm_early_init)(); - if (error) - goto module_early_init_failed; - - error = tf_device_mshield_init(smc_mem); - if (error) - goto mshield_init_failed; - -#ifdef CONFIG_TF_DRIVER_CRYPTO_FIPS - error = tf_crypto_hmac_module_init(); - if (error) - goto hmac_init_failed; - - error = tf_self_test_register_device(); - if (error) - goto self_test_register_device_failed; -#endif -#endif - - /* register the sysfs object driver stats */ - error = kobject_init_and_add(&dev->kobj, &tf_ktype, NULL, "%s", - TF_DEVICE_BASE_NAME); - if (error) { - printk(KERN_ERR "tf_device_register(): " - "kobject_init_and_add failed (error %d)!\n", error); - kobject_put(&dev->kobj); - goto kobject_init_and_add_failed; - } - - /* - * Register the system device. - */ - register_syscore_ops(&g_tf_device_syscore_ops); - - /* - * Register the char device. - */ - printk(KERN_INFO "Registering char device %s (%u:%u)\n", - TF_DEVICE_BASE_NAME, - MAJOR(dev->dev_number), - MINOR(dev->dev_number)); - error = register_chrdev_region(dev->dev_number, 1, - TF_DEVICE_BASE_NAME); - if (error != 0) { - printk(KERN_ERR "tf_device_register():" - " register_chrdev_region failed (error %d)!\n", - error); - goto register_chrdev_region_failed; - } - - error = cdev_add(&dev->cdev, dev->dev_number, 1); - if (error != 0) { - printk(KERN_ERR "tf_device_register(): " - "cdev_add failed (error %d)!\n", - error); - goto cdev_add_failed; - } - - /* - * Initialize the communication with the Secure World. - */ -#ifdef CONFIG_TF_TRUSTZONE - dev->sm.soft_int_irq = soft_interrupt; -#endif - error = tf_init(&g_tf_dev.sm); - if (error != S_SUCCESS) { - dprintk(KERN_ERR "tf_device_register(): " - "tf_init failed (error %d)!\n", - error); - goto init_failed; - } - -#ifdef CONFIG_TF_DRIVER_CRYPTO_FIPS - error = tf_self_test_post_init(&(g_tf_dev.kobj)); - /* N.B. error > 0 indicates a POST failure, which will not - prevent the module from loading. */ - if (error < 0) { - dprintk(KERN_ERR "tf_device_register(): " - "tf_self_test_post_vectors failed (error %d)!\n", - error); - goto post_failed; - } -#endif - -#ifdef CONFIG_ANDROID - tf_class = class_create(THIS_MODULE, TF_DEVICE_BASE_NAME); - device_create(tf_class, NULL, - dev->dev_number, - NULL, TF_DEVICE_BASE_NAME); -#endif - -#ifdef CONFIG_TF_ZEBRA - /* - * Initializes the /dev/tf_ctrl device node. - */ - error = tf_ctrl_device_register(); - if (error) - goto ctrl_failed; -#endif - -#ifdef CONFIG_TF_DRIVER_DEBUG_SUPPORT - address_cache_property((unsigned long) &tf_device_register); -#endif - /* - * Successful completion. - */ - - dprintk(KERN_INFO "tf_device_register(): Success\n"); - return 0; - - /* - * Error: undo all operations in the reverse order - */ -#ifdef CONFIG_TF_ZEBRA -ctrl_failed: -#endif -#ifdef CONFIG_TF_DRIVER_CRYPTO_FIPS - tf_self_test_post_exit(); -post_failed: -#endif -init_failed: - cdev_del(&dev->cdev); -cdev_add_failed: - unregister_chrdev_region(dev->dev_number, 1); -register_chrdev_region_failed: - unregister_syscore_ops(&g_tf_device_syscore_ops); -kobject_init_and_add_failed: - kobject_del(&g_tf_dev.kobj); - -#if defined(MODULE) && defined(CONFIG_TF_ZEBRA) -#ifdef CONFIG_TF_DRIVER_CRYPTO_FIPS - tf_self_test_unregister_device(); -self_test_register_device_failed: - tf_crypto_hmac_module_exit(); -hmac_init_failed: -#endif - tf_device_mshield_exit(); -mshield_init_failed: -module_early_init_failed: -#endif - dprintk(KERN_INFO "tf_device_register(): Failure (error %d)\n", - error); - return error; -} - -/*----------------------------------------------------------------------------*/ - -static int tf_device_open(struct inode *inode, struct file *file) -{ - int error; - struct tf_device *dev = &g_tf_dev; - struct tf_connection *connection = NULL; - - dprintk(KERN_INFO "tf_device_open(%u:%u, %p)\n", - imajor(inode), iminor(inode), file); - - /* Dummy lseek for non-seekable driver */ - error = nonseekable_open(inode, file); - if (error != 0) { - dprintk(KERN_ERR "tf_device_open(%p): " - "nonseekable_open failed (error %d)!\n", - file, error); - goto error; - } - -#ifndef CONFIG_ANDROID - /* - * Check file flags. We only autthorize the O_RDWR access - */ - if (file->f_flags != O_RDWR) { - dprintk(KERN_ERR "tf_device_open(%p): " - "Invalid access mode %u\n", - file, file->f_flags); - error = -EACCES; - goto error; - } -#endif - - /* - * Open a new connection. - */ - - error = tf_open(dev, file, &connection); - if (error != 0) { - dprintk(KERN_ERR "tf_device_open(%p): " - "tf_open failed (error %d)!\n", - file, error); - goto error; - } - - file->private_data = connection; - - /* - * Send the CreateDeviceContext command to the secure - */ - error = tf_create_device_context(connection); - if (error != 0) { - dprintk(KERN_ERR "tf_device_open(%p): " - "tf_create_device_context failed (error %d)!\n", - file, error); - goto error1; - } - - /* - * Successful completion. - */ - - dprintk(KERN_INFO "tf_device_open(%p): Success (connection=%p)\n", - file, connection); - return 0; - - /* - * Error handling. - */ - -error1: - tf_close(connection); -error: - dprintk(KERN_INFO "tf_device_open(%p): Failure (error %d)\n", - file, error); - return error; -} - -/*----------------------------------------------------------------------------*/ - -static int tf_device_release(struct inode *inode, struct file *file) -{ - struct tf_connection *connection; - - dprintk(KERN_INFO "tf_device_release(%u:%u, %p)\n", - imajor(inode), iminor(inode), file); - - connection = tf_conn_from_file(file); - tf_close(connection); - - dprintk(KERN_INFO "tf_device_release(%p): Success\n", file); - return 0; -} - -/*----------------------------------------------------------------------------*/ - -static long tf_device_ioctl(struct file *file, unsigned int ioctl_num, - unsigned long ioctl_param) -{ - int result = S_SUCCESS; - struct tf_connection *connection; - union tf_command command; - struct tf_command_header header; - union tf_answer answer; - u32 command_size; - u32 answer_size; - void *user_answer; - - dprintk(KERN_INFO "tf_device_ioctl(%p, %u, %p)\n", - file, ioctl_num, (void *) ioctl_param); - - switch (ioctl_num) { - case IOCTL_TF_GET_VERSION: - /* ioctl is asking for the driver interface version */ - result = TF_DRIVER_INTERFACE_VERSION; - goto exit; - -#ifdef CONFIG_TF_ION - case IOCTL_TF_ION_REGISTER: { - int ion_register; - /* ioctl is asking to register an ion handle */ - if (copy_from_user(&ion_register, - (int *) ioctl_param, - sizeof(int))) { - dprintk(KERN_ERR "tf_device_ioctl(%p): " - "copy_from_user failed\n", - file); - result = -EFAULT; - goto exit; - } - - connection = tf_conn_from_file(file); - BUG_ON(connection == NULL); - - /* Initialize ION connection */ - if (connection->ion_client == NULL) { - connection->ion_client = ion_client_create( - zebra_ion_device, - (1 << ION_HEAP_TYPE_CARVEOUT), - "tf"); - } - - if (connection->ion_client == NULL) { - dprintk(KERN_ERR "tf_device_ioctl(%p): " - "unable to create ion client\n", - file); - result = -EFAULT; - goto exit; - } - - /* - * TODO: We should use a reference count on this handle in order - * to not unregistered it while using it. - */ - return (long)ion_import_fd(connection->ion_client, ion_register); - } - - case IOCTL_TF_ION_UNREGISTER: { - int ion_register; - /* ioctl is asking to unregister an ion handle */ - - if (copy_from_user(&ion_register, - (int *) ioctl_param, - sizeof(int))) { - dprintk(KERN_ERR "tf_device_ioctl(%p): " - "copy_from_user failed\n", - file); - result = -EFAULT; - goto exit; - } - - connection = tf_conn_from_file(file); - BUG_ON(connection == NULL); - - if (connection->ion_client == NULL) { - dprintk(KERN_ERR "tf_device_ioctl(%p): " - "ion client does not exist\n", - file); - result = -EFAULT; - goto exit; - } - - ion_free(connection->ion_client, - (struct ion_handle *) ion_register); - - return S_SUCCESS; - } -#endif - - case IOCTL_TF_EXCHANGE: - /* - * ioctl is asking to perform a message exchange with the Secure - * Module - */ - - /* - * Make a local copy of the data from the user application - * This routine checks the data is readable - * - * Get the header first. - */ - if (copy_from_user(&header, - (struct tf_command_header *)ioctl_param, - sizeof(struct tf_command_header))) { - dprintk(KERN_ERR "tf_device_ioctl(%p): " - "Cannot access ioctl parameter %p\n", - file, (void *) ioctl_param); - result = -EFAULT; - goto exit; - } - - /* size in words of u32 */ - command_size = header.message_size + - sizeof(struct tf_command_header)/sizeof(u32); - if (command_size > sizeof(command)/sizeof(u32)) { - dprintk(KERN_ERR "tf_device_ioctl(%p): " - "Buffer overflow: too many bytes to copy %d\n", - file, command_size); - result = -EFAULT; - goto exit; - } - - if (copy_from_user(&command, - (union tf_command *)ioctl_param, - command_size * sizeof(u32))) { - dprintk(KERN_ERR "tf_device_ioctl(%p): " - "Cannot access ioctl parameter %p\n", - file, (void *) ioctl_param); - result = -EFAULT; - goto exit; - } - - connection = tf_conn_from_file(file); - BUG_ON(connection == NULL); - - /* - * The answer memory space address is in the operation_id field - */ - user_answer = (void *) command.header.operation_id; - - atomic_inc(&(connection->pending_op_count)); - - dprintk(KERN_WARNING "tf_device_ioctl(%p): " - "Sending message type 0x%08x\n", - file, command.header.message_type); - - switch (command.header.message_type) { - case TF_MESSAGE_TYPE_OPEN_CLIENT_SESSION: - result = tf_open_client_session(connection, - &command, &answer); - break; - - case TF_MESSAGE_TYPE_CLOSE_CLIENT_SESSION: - result = tf_close_client_session(connection, - &command, &answer); - break; - - case TF_MESSAGE_TYPE_REGISTER_SHARED_MEMORY: - result = tf_register_shared_memory(connection, - &command, &answer); - break; - - case TF_MESSAGE_TYPE_RELEASE_SHARED_MEMORY: - result = tf_release_shared_memory(connection, - &command, &answer); - break; - - case TF_MESSAGE_TYPE_INVOKE_CLIENT_COMMAND: - trace_invoke_client_command(NVSEC_INVOKE_CMD_START); - result = tf_invoke_client_command(connection, - &command, &answer); - trace_invoke_client_command(NVSEC_INVOKE_CMD_DONE); - break; - - case TF_MESSAGE_TYPE_CANCEL_CLIENT_COMMAND: - result = tf_cancel_client_command(connection, - &command, &answer); - break; - - default: - dprintk(KERN_ERR "tf_device_ioctl(%p): " - "Incorrect message type (0x%08x)!\n", - connection, command.header.message_type); - result = -EOPNOTSUPP; - break; - } - - atomic_dec(&(connection->pending_op_count)); - - if (result != 0) { - dprintk(KERN_WARNING "tf_device_ioctl(%p): " - "Operation returning error code 0x%08x)!\n", - file, result); - goto exit; - } - - /* - * Copy the answer back to the user space application. - * The driver does not check this field, only copy back to user - * space the data handed over by Secure World - */ - answer_size = answer.header.message_size + - sizeof(struct tf_answer_header)/sizeof(u32); - if (copy_to_user(user_answer, - &answer, answer_size * sizeof(u32))) { - dprintk(KERN_WARNING "tf_device_ioctl(%p): " - "Failed to copy back the full command " - "answer to %p\n", file, user_answer); - result = -EFAULT; - goto exit; - } - - /* successful completion */ - dprintk(KERN_INFO "tf_device_ioctl(%p): Success\n", file); - break; - - case IOCTL_TF_GET_DESCRIPTION: { - /* ioctl asking for the version information buffer */ - struct tf_version_information_buffer *pInfoBuffer; - - dprintk(KERN_INFO "IOCTL_TF_GET_DESCRIPTION:(%p, %u, %p)\n", - file, ioctl_num, (void *) ioctl_param); - - pInfoBuffer = - ((struct tf_version_information_buffer *) ioctl_param); - - dprintk(KERN_INFO "IOCTL_TF_GET_DESCRIPTION1: " - "driver_description=\"%64s\"\n", S_VERSION_STRING); - - if (copy_to_user(pInfoBuffer->driver_description, - S_VERSION_STRING, - strlen(S_VERSION_STRING) + 1)) { - dprintk(KERN_ERR "tf_device_ioctl(%p): " - "Fail to copy back the driver description " - "to %p\n", - file, pInfoBuffer->driver_description); - result = -EFAULT; - goto exit; - } - - dprintk(KERN_INFO "IOCTL_TF_GET_DESCRIPTION2: " - "secure_world_description=\"%64s\"\n", - tf_get_description(&g_tf_dev.sm)); - - if (copy_to_user(pInfoBuffer->secure_world_description, - tf_get_description(&g_tf_dev.sm), - TF_DESCRIPTION_BUFFER_LENGTH)) { - dprintk(KERN_WARNING "tf_device_ioctl(%p): " - "Failed to copy back the secure world " - "description to %p\n", - file, pInfoBuffer->secure_world_description); - result = -EFAULT; - goto exit; - } - break; - } - - default: - dprintk(KERN_ERR "tf_device_ioctl(%p): " - "Unknown IOCTL code 0x%08x!\n", - file, ioctl_num); - result = -EOPNOTSUPP; - goto exit; - } - -exit: - return result; -} - -/*----------------------------------------------------------------------------*/ - -static void tf_device_shutdown(void) -{ - if (0 > tf_power_management(&g_tf_dev.sm, TF_POWER_OPERATION_SHUTDOWN)) - dprintk(KERN_ERR "tf_device_shutdown failing\n"); -} - -/*----------------------------------------------------------------------------*/ - -static int tf_device_suspend(void) -{ - dprintk(KERN_INFO "tf_device_suspend: Enter\n"); - return tf_power_management(&g_tf_dev.sm, - TF_POWER_OPERATION_HIBERNATE); -} - - -/*----------------------------------------------------------------------------*/ - -static void tf_device_resume(void) -{ - if (0 > tf_power_management(&g_tf_dev.sm, TF_POWER_OPERATION_RESUME)) - dprintk(KERN_ERR "tf_device_resume failing\n"); -} - - -/*----------------------------------------------------------------------------*/ - -module_init(tf_device_register); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Trusted Logic S.A."); |