aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/sensorhub/ssp_sensorhub.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/sensorhub/ssp_sensorhub.c')
-rw-r--r--drivers/sensorhub/ssp_sensorhub.c574
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");