diff options
Diffstat (limited to 'drivers/sensorhub/ssp_sensorhub.c')
-rw-r--r-- | drivers/sensorhub/ssp_sensorhub.c | 574 |
1 files changed, 0 insertions, 574 deletions
diff --git a/drivers/sensorhub/ssp_sensorhub.c b/drivers/sensorhub/ssp_sensorhub.c deleted file mode 100644 index bfa80d0..0000000 --- a/drivers/sensorhub/ssp_sensorhub.c +++ /dev/null @@ -1,574 +0,0 @@ -/* - * Copyright (C) 2012, Samsung Electronics Co. Ltd. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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. - * - */ - -#include "ssp.h" - -static const struct fast_data { - char library_data[3]; -} fast_data_table[] = { - { { 1, 1, 7 } }, -}; - -static ssize_t ssp_sensorhub_write(struct file *file, const char __user *buf, - size_t count, loff_t *pos) -{ - struct ssp_sensorhub_data *hub_data - = container_of(file->private_data, - struct ssp_sensorhub_data, sensorhub_device); - int ret = 0; - int i; - u8 instruction = buf[0]; - - if (count == 0) { - pr_err("%s: library command length err(%d)", __func__, count); - return -EINVAL; - } - - for (i = 0; i < count; i++) - pr_info("%s[%d] = 0x%x", __func__, i, buf[i]); - - if (buf[0] == MSG2SSP_INST_LIBRARY_REMOVE) - instruction = REMOVE_LIBRARY; - else if (buf[0] == MSG2SSP_INST_LIBRARY_ADD) - instruction = ADD_LIBRARY; - - if (hub_data->ssp_data->bSspShutdown) { - pr_err("%s: stop sending command(no ssp_data)", __func__); - return -ENOMEM; - } - - ret = send_instruction(hub_data->ssp_data, instruction, - (u8)buf[1], (u8 *)(buf+2), count-2); - if (ret <= 0) - pr_err("%s: send library command err(%d)", __func__, ret); - - /* i2c transfer fail */ - if (ret == ERROR) - return -EIO; - /* no ack from MCU */ - else if (ret == FAIL) - return -EAGAIN; - /* success */ - else - return count; -} - -static long ssp_sensorhub_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) -{ - void __user *argp = (void __user *)arg; - struct ssp_sensorhub_data *hub_data - = container_of(file->private_data, - struct ssp_sensorhub_data, sensorhub_device); - int ret = 0; - int i = 0; - - switch (cmd) { - case IOCTL_READ_CONTEXT_DATA: - /* for receive_msg */ - if (!hub_data->large_library_length && - hub_data->large_library_data == NULL) { - - ret = copy_to_user(argp, - hub_data->first_event->library_data, - hub_data->first_event->length); - if (ret < 0) { - pr_err("%s: send library data err(%d)", - __func__, ret); - complete(&hub_data->transfer_done); - goto exit; - } - - for (i = 0; i < hub_data->first_event->length; i++) { - pr_info("%s[%d] = 0x%x", __func__, i, - hub_data->first_event->library_data[i]); - } - - hub_data->transfer_try = 0; - complete(&hub_data->transfer_done); - - /* for receive_large_msg */ - } else { - pr_info("%s: receive_large_msg ioctl", __func__); - ret = copy_to_user(argp, hub_data->large_library_data, - hub_data->large_library_length); - if (ret < 0) { - pr_err("%s: send large library data err(%d)", - __func__, ret); - goto exit; - } - - kfree(hub_data->large_library_data); - hub_data->large_library_length = 0; - } - break; - - default: - pr_err("%s: icotl cmd err(%d)", __func__, cmd); - ret = -EINVAL; - } - -exit: - return ret; -} - -static struct file_operations ssp_sensorhub_fops = { - .owner = THIS_MODULE, - .open = nonseekable_open, - .write = ssp_sensorhub_write, - .unlocked_ioctl = ssp_sensorhub_ioctl, -}; - -void ssp_report_sensorhub_notice(struct ssp_data *ssp_data, char notice) -{ - struct ssp_sensorhub_data *hub_data = ssp_data->hub_data; - - input_report_rel(hub_data->sensorhub_input_dev, REL_RY, notice); - input_sync(hub_data->sensorhub_input_dev); - - if (notice == MSG2SSP_AP_STATUS_WAKEUP) - pr_info("%s: wake up", __func__); - else if (notice == MSG2SSP_AP_STATUS_SLEEP) - pr_info("%s: sleep", __func__); - else if (notice == MSG2SSP_AP_STATUS_RESET) - pr_info("%s: reset", __func__); - else - pr_err("%s: invalid notice", __func__); -} - -static void ssp_report_sensorhub_length(struct ssp_sensorhub_data *hub_data, - int length) -{ - input_report_rel(hub_data->sensorhub_input_dev, REL_RX, length); - input_sync(hub_data->sensorhub_input_dev); - pr_info("%s = %d", __func__, length); -} - -static int ssp_sensorhub_is_fast_data(char *data, int start) -{ - int i, j; - - for (i = 0; i < ARRAY_SIZE(fast_data_table); i++) { - for (j = 0; j < sizeof(fast_data_table[0]); j++) { - if (data[start + j] != - fast_data_table[i].library_data[j]) - break; - } - if (j == sizeof(fast_data_table[0])) - return i; - } - - return -EINVAL; -} - -static int ssp_queue_sensorhub_events(struct ssp_sensorhub_data *hub_data, - char *dataframe, int start, int end) -{ - struct sensorhub_event *event; - int length = end - start; - int event_number = hub_data->event_number; - int events = 0; - int ret = 0; - int i = 0; - - if (length <= 0) { - pr_err("%s: library length err(%d)", __func__, length); - return -EINVAL; - } - - /* how many events in the list? */ - spin_lock_bh(&hub_data->sensorhub_lock); - list_for_each_entry(event, &hub_data->events_head.list, list) - events++; - spin_unlock_bh(&hub_data->sensorhub_lock); - - /* drop event if queue is full */ - if (events >= LIBRARY_MAX_NUM) { - pr_info("%s: queue is full", __func__); - hub_data->transfer_ready++; - ret = ssp_sensorhub_is_fast_data(dataframe, start); - if (ret >= 0) - event_number = LIBRARY_MAX_NUM + ret; - else - return -ENOMEM; - } - - /* allocate memory for new event */ - if (hub_data->events[event_number].library_data != NULL) - kfree(hub_data->events[event_number].library_data); - - hub_data->events[event_number].library_data - = kzalloc(length * sizeof(char), GFP_KERNEL); - if (hub_data->events[event_number].library_data == NULL) { - pr_err("%s: allocate memory for library data err", __func__); - return -ENOMEM; - } - - /* copy sensorhub event into queue */ - while (start < end) { - hub_data->events[event_number].library_data[i++] - = dataframe[start++]; - pr_info("%s[%d] = 0x%x", __func__, i-1, - hub_data->events[event_number].library_data[i-1]); - } - hub_data->events[event_number].length = length; - - if (events <= LIBRARY_MAX_NUM) { - /* add new event at the end of queue */ - spin_lock_bh(&hub_data->sensorhub_lock); - list_add_tail(&hub_data->events[event_number].list, - &hub_data->events_head.list); - if (events++ < LIBRARY_MAX_NUM) - hub_data->transfer_ready = 0; - spin_unlock_bh(&hub_data->sensorhub_lock); - - /* do not exceed max queue number */ - if (hub_data->event_number++ >= LIBRARY_MAX_NUM - 1) - hub_data->event_number = 0; - } else { - spin_lock_bh(&hub_data->sensorhub_lock); - list_replace(hub_data->events_head.list.prev, - &hub_data->events[event_number].list); - spin_unlock_bh(&hub_data->sensorhub_lock); - } - - pr_info("%s: total %d events", __func__, events); - return events; -} - -static int ssp_receive_large_msg(struct ssp_sensorhub_data *hub_data, - u8 sub_cmd) -{ - char send_data[2] = { 0, }; - char receive_data[2] = { 0, }; - char *large_msg_data; /* Nth large msg data */ - int length = 0; /* length of Nth large msg */ - int data_locater = 0; /* large_library_data current position */ - int total_msg_number; /* total number of large msg */ - int msg_number; /* current number of large msg */ - int ret = 0; - - /* receive the first msg length */ - send_data[0] = MSG2SSP_STT; - send_data[1] = sub_cmd; - - /* receive_data(msg length) is two byte because msg is large */ - ret = ssp_i2c_read(hub_data->ssp_data, send_data, 2, - receive_data, 2, 0); - if (ret < 0) { - pr_err("%s: MSG2SSP_STT i2c err(%d)", __func__, ret); - return ret; - } - - /* get the first msg length */ - length = ((unsigned int)receive_data[0] << 8) - + (unsigned int)receive_data[1]; - if (length < 3) { - /* do not print err message with power-up */ - if (sub_cmd != SUBCMD_POWEREUP) - pr_err("%s: 1st large msg data not ready(length=%d)", - __func__, length); - return -EINVAL; - } - - /* receive the first msg data */ - send_data[0] = MSG2SSP_SRM; - large_msg_data = kzalloc((length * sizeof(char)), GFP_KERNEL); - ret = ssp_i2c_read(hub_data->ssp_data, send_data, 1, - large_msg_data, length, 0); - if (ret < 0) { - pr_err("%s: receive 1st large msg err(%d)", __func__, ret); - kfree(large_msg_data); - return ret; - } - - /* empty the previous large library data */ - if (hub_data->large_library_length != 0) - kfree(hub_data->large_library_data); - - /* large_msg_data[0] of the first msg: total number of large msg - * large_msg_data[1-2] of the first msg: total msg length - * large_msg_data[3-N] of the first msg: the first msg data itself */ - total_msg_number = large_msg_data[0]; - hub_data->large_library_length - = (int)((unsigned int)large_msg_data[1] << 8) - + (unsigned int)large_msg_data[2]; - hub_data->large_library_data - = kzalloc((hub_data->large_library_length * sizeof(char)), - GFP_KERNEL); - - /* copy the fist msg data into large_library_data */ - memcpy(hub_data->large_library_data, &large_msg_data[3], - (length - 3) * sizeof(char)); - kfree(large_msg_data); - - data_locater = length - 3; - - /* 2nd, 3rd,...Nth msg */ - for (msg_number = 0; msg_number < total_msg_number; msg_number++) { - /* receive Nth msg length */ - send_data[0] = MSG2SSP_STT; - send_data[1] = 0x81 + msg_number; - - /* receive_data(msg length) is two byte because msg is large */ - ret = ssp_i2c_read(hub_data->ssp_data, send_data, 2, - receive_data, 2, 0); - if (ret < 0) { - pr_err("%s: MSG2SSP_STT i2c err(%d)", - __func__, ret); - return ret; - } - - /* get the Nth msg length */ - length = ((unsigned int)receive_data[0] << 8) - + (unsigned int)receive_data[1]; - if (length <= 0) { - pr_err("%s: %dth large msg data not ready(length=%d)", - __func__, msg_number + 2, length); - return -EINVAL; - } - - large_msg_data = kzalloc((length * sizeof(char)), - GFP_KERNEL); - - /* receive Nth msg data */ - send_data[0] = MSG2SSP_SRM; - ret = ssp_i2c_read(hub_data->ssp_data, send_data, 1, - large_msg_data, length, 0); - if (ret < 0) { - pr_err("%s: recieve %dth large msg err(%d)", - __func__, msg_number + 2, ret); - kfree(large_msg_data); - return ret; - } - - /* copy(append) Nth msg data into large_library_data */ - memcpy(&hub_data->large_library_data[data_locater], - large_msg_data, length * sizeof(char)); - data_locater += length; - kfree(large_msg_data); - } - - return hub_data->large_library_length; -} - -static int ssp_senosrhub_thread_func(void *arg) -{ - struct ssp_sensorhub_data *hub_data = (struct ssp_sensorhub_data *)arg; - struct sensorhub_event *event; - int events = 0; - int ret = 0; - - while (!kthread_should_stop()) { - /* run if only event queue is not empty */ - wait_event_interruptible(hub_data->sensorhub_waitqueue, - kthread_should_stop() || - !list_empty(&hub_data->events_head.list)); - - /* exit thread if kthread should stop */ - if (unlikely(kthread_should_stop())) { - pr_info("%s: kthread_stop()", __func__); - break; - } - - /* exit thread - * if user does not get data with consecutive trials - */ - if (unlikely(hub_data->transfer_try++ >= LIBRARY_MAX_TRY)) { - pr_err("%s: user does not get data", __func__); - break; - } - - /* report sensorhub event to user */ - if (hub_data->transfer_ready == 0) { - /* first in first out */ - hub_data->first_event - = list_first_entry(&hub_data->events_head.list, - struct sensorhub_event, list); - if (IS_ERR(hub_data->first_event)) { - pr_err("%s: first event err(%ld)", __func__, - PTR_ERR(hub_data->first_event)); - continue; - } - - /* report sensorhub event to user */ - ssp_report_sensorhub_length(hub_data, - hub_data->first_event->length); - wake_lock_timeout(&hub_data->sensorhub_wake_lock, 5*HZ); - hub_data->transfer_ready++; - } - - /* wait until user gets data */ - ret = wait_for_completion_timeout(&hub_data->transfer_done, - 3*HZ); - if (ret == 0) { - pr_err("%s: wait timed out", __func__); - hub_data->transfer_ready = 0; - } else if (ret < 0) { - pr_err("%s: wait_for_completion_timeout err(%d)", - __func__, ret); - } - - /* remove first event only if transfer succeed */ - if (hub_data->transfer_try == 0) { - /* remove first event */ - spin_lock_bh(&hub_data->sensorhub_lock); - if (!list_empty(&hub_data->events_head.list)) - list_del(&hub_data->first_event->list); - hub_data->transfer_ready = 0; - - /* how many events in the list? */ - events = 0; - list_for_each_entry(event, - &hub_data->events_head.list, list) - events++; - spin_unlock_bh(&hub_data->sensorhub_lock); - - pr_info("%s: %d events remain", __func__, events); - continue; - } - - /* throw away extra events */ - if (hub_data->transfer_ready > EVENT_WAIT_COUNT) - hub_data->transfer_ready = 0; - - usleep_range(10000, 10000); - } - - pr_info("%s: exit", __func__); - return ret; -} - -int ssp_handle_sensorhub_data(struct ssp_data *ssp_data, char *dataframe, - int start, int end) -{ - struct ssp_sensorhub_data *hub_data = ssp_data->hub_data; - - /* add new sensorhub event into queue */ - int ret = ssp_queue_sensorhub_events(hub_data, dataframe, start, end); - wake_up(&hub_data->sensorhub_waitqueue); - - return ret; -} - -int ssp_handle_sensorhub_large_data(struct ssp_data *ssp_data, u8 sub_cmd) -{ - struct ssp_sensorhub_data *hub_data = ssp_data->hub_data; - - /* receive large size of library data */ - int ret = ssp_receive_large_msg(hub_data, sub_cmd); - if (ret >= 0) { - ssp_report_sensorhub_length(hub_data, - hub_data->large_library_length); - wake_lock_timeout(&hub_data->sensorhub_wake_lock, 3*HZ); - } else { - pr_err("%s: ssp_receive_large_msg err(%d)", __func__, ret); - } - - return ret; -} - -int ssp_initialize_sensorhub(struct ssp_data *ssp_data) -{ - struct ssp_sensorhub_data *hub_data; - int ret; - - hub_data = kzalloc(sizeof(*hub_data), GFP_KERNEL); - if (!hub_data) { - pr_err("%s: failed to allocate memory for sensorhub data", - __func__); - return -ENOMEM; - } - hub_data->ssp_data = ssp_data; - ssp_data->hub_data = hub_data; - - /* allocate sensorhub input devices */ - hub_data->sensorhub_input_dev = input_allocate_device(); - if (!hub_data->sensorhub_input_dev) { - pr_err("%s: allocate sensorhub input devices err", __func__); - ret = -ENOMEM; - goto err_input_allocate_device_sensorhub; - } - - wake_lock_init(&hub_data->sensorhub_wake_lock, WAKE_LOCK_SUSPEND, - "sensorhub_wake_lock"); - INIT_LIST_HEAD(&hub_data->events_head.list); - init_waitqueue_head(&hub_data->sensorhub_waitqueue); - init_completion(&hub_data->transfer_done); - spin_lock_init(&hub_data->sensorhub_lock); - - ret = input_register_device(hub_data->sensorhub_input_dev); - if (ret < 0) { - pr_err("%s: could not register sensorhub input device(%d)", - __func__, ret); - input_free_device(hub_data->sensorhub_input_dev); - goto err_input_register_device_sensorhub; - } - - hub_data->sensorhub_input_dev->name = "ssp_context"; - input_set_drvdata(hub_data->sensorhub_input_dev, hub_data); - input_set_capability(hub_data->sensorhub_input_dev, EV_REL, REL_RX); - input_set_capability(hub_data->sensorhub_input_dev, EV_REL, REL_RY); - - /* create sensorhub device node */ - hub_data->sensorhub_device.minor = MISC_DYNAMIC_MINOR; - hub_data->sensorhub_device.name = "ssp_sensorhub"; - hub_data->sensorhub_device.fops = &ssp_sensorhub_fops; - - ret = misc_register(&hub_data->sensorhub_device); - if (ret < 0) { - pr_err("%s: misc_register() failed", __func__); - goto err_misc_register; - } - - hub_data->sensorhub_task = kthread_run(ssp_senosrhub_thread_func, - (void *)hub_data, "ssp_sensorhub_task"); - if (IS_ERR(hub_data->sensorhub_task)) { - ret = PTR_ERR(hub_data->sensorhub_task); - goto err_kthread_create; - } - - return 0; - -err_kthread_create: - misc_deregister(&hub_data->sensorhub_device); -err_misc_register: - input_unregister_device(hub_data->sensorhub_input_dev); -err_input_register_device_sensorhub: - complete_all(&hub_data->transfer_done); - wake_lock_destroy(&hub_data->sensorhub_wake_lock); -err_input_allocate_device_sensorhub: - kfree(hub_data); - return ret; -} - -void ssp_remove_sensorhub(struct ssp_data *ssp_data) -{ - struct ssp_sensorhub_data *hub_data = ssp_data->hub_data; - - ssp_sensorhub_fops.write = NULL; - ssp_sensorhub_fops.unlocked_ioctl = NULL; - misc_deregister(&hub_data->sensorhub_device); - input_unregister_device(hub_data->sensorhub_input_dev); - wake_lock_destroy(&hub_data->sensorhub_wake_lock); - complete_all(&hub_data->transfer_done); - if (hub_data->sensorhub_task) - kthread_stop(hub_data->sensorhub_task); - kfree(hub_data); -} - -MODULE_DESCRIPTION("Samsung Sensor Platform(SSP) sensorhub driver"); -MODULE_AUTHOR("Samsung Electronics"); -MODULE_LICENSE("GPL"); |