/* * Copyright (C) 2010-2013 Motorola Mobility LLC * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include int stm401_as_data_buffer_write(struct stm401_data *ps_stm401, unsigned char type, unsigned char *data, int size, unsigned char status) { int new_head; struct stm401_android_sensor_data *buffer; struct timespec ts; static bool error_reported; new_head = (ps_stm401->stm401_as_data_buffer_head + 1) & STM401_AS_DATA_QUEUE_MASK; if (new_head == ps_stm401->stm401_as_data_buffer_tail) { if (!error_reported) { dev_err(&ps_stm401->client->dev, "as data buffer full\n"); error_reported = true; } wake_up(&ps_stm401->stm401_as_data_wq); return 0; } buffer = &(ps_stm401->stm401_as_data_buffer[new_head]); buffer->type = type; buffer->status = status; if (data != NULL && size > 0) { if (size > sizeof(buffer->data)) { dev_err(&ps_stm401->client->dev, "size %d exceeds as buffer\n", size); return 0; } memcpy(buffer->data, data, size); } buffer->size = size; ktime_get_ts(&ts); buffer->timestamp = ts.tv_sec*1000000000LL + ts.tv_nsec; ps_stm401->stm401_as_data_buffer_head = new_head; wake_up(&ps_stm401->stm401_as_data_wq); error_reported = false; return 1; } int stm401_as_data_buffer_read(struct stm401_data *ps_stm401, struct stm401_android_sensor_data *buff) { int new_tail; if (ps_stm401->stm401_as_data_buffer_tail == ps_stm401->stm401_as_data_buffer_head) return 0; new_tail = (ps_stm401->stm401_as_data_buffer_tail + 1) & STM401_AS_DATA_QUEUE_MASK; *buff = ps_stm401->stm401_as_data_buffer[new_tail]; ps_stm401->stm401_as_data_buffer_tail = new_tail; return 1; } int stm401_ms_data_buffer_write(struct stm401_data *ps_stm401, unsigned char type, unsigned char *data, int size) { int new_head; struct stm401_moto_sensor_data *buffer; struct timespec ts; static bool error_reported; new_head = (ps_stm401->stm401_ms_data_buffer_head + 1) & STM401_MS_DATA_QUEUE_MASK; if (new_head == ps_stm401->stm401_ms_data_buffer_tail) { if (!error_reported) { dev_err(&ps_stm401->client->dev, "ms data buffer full\n"); error_reported = true; } wake_up(&ps_stm401->stm401_ms_data_wq); return 0; } buffer = &(ps_stm401->stm401_ms_data_buffer[new_head]); buffer->type = type; if (data != NULL && size > 0) { if (size > sizeof(buffer->data)) { dev_err(&ps_stm401->client->dev, "size %d exceeds ms buffer\n", size); return 0; } memcpy(buffer->data, data, size); } buffer->size = size; ktime_get_ts(&ts); buffer->timestamp = ts.tv_sec*1000000000LL + ts.tv_nsec; ps_stm401->stm401_ms_data_buffer_head = new_head; wake_up(&ps_stm401->stm401_ms_data_wq); error_reported = false; return 1; } int stm401_ms_data_buffer_read(struct stm401_data *ps_stm401, struct stm401_moto_sensor_data *buff) { int new_tail; if (ps_stm401->stm401_ms_data_buffer_tail == ps_stm401->stm401_ms_data_buffer_head) return 0; new_tail = (ps_stm401->stm401_ms_data_buffer_tail + 1) & STM401_MS_DATA_QUEUE_MASK; *buff = ps_stm401->stm401_ms_data_buffer[new_tail]; ps_stm401->stm401_ms_data_buffer_tail = new_tail; return 1; } static int stm401_as_open(struct inode *inode, struct file *file) { int err = 0; dev_dbg(&stm401_misc_data->client->dev, "stm401_as_open\n"); err = nonseekable_open(inode, file); if (err < 0) return err; file->private_data = stm401_misc_data; return err; } static ssize_t stm401_as_read(struct file *file, char __user *buffer, size_t size, loff_t *ppos) { int ret; struct stm401_android_sensor_data tmp_buff; struct stm401_data *ps_stm401 = file->private_data; ret = stm401_as_data_buffer_read(ps_stm401, &tmp_buff); if (ret == 0) return 0; ret = copy_to_user(buffer, &tmp_buff, sizeof(struct stm401_android_sensor_data)); if (ret != 0) { dev_err(&ps_stm401->client->dev, "Copy error\n"); return 0; } return sizeof(struct stm401_android_sensor_data); } static unsigned int stm401_as_poll(struct file *file, struct poll_table_struct *wait) { unsigned int mask = 0; struct stm401_data *ps_stm401 = file->private_data; poll_wait(file, &ps_stm401->stm401_as_data_wq, wait); if (ps_stm401->stm401_as_data_buffer_head != ps_stm401->stm401_as_data_buffer_tail) mask = POLLIN | POLLRDNORM; return mask; } const struct file_operations stm401_as_fops = { .owner = THIS_MODULE, .open = stm401_as_open, .read = stm401_as_read, .poll = stm401_as_poll, }; static int stm401_ms_open(struct inode *inode, struct file *file) { int err = 0; dev_dbg(&stm401_misc_data->client->dev, "stm401_ms_open\n"); err = nonseekable_open(inode, file); if (err < 0) return err; file->private_data = stm401_misc_data; return err; } static ssize_t stm401_ms_read(struct file *file, char __user *buffer, size_t size, loff_t *ppos) { int ret; struct stm401_moto_sensor_data tmp_buff; struct stm401_data *ps_stm401 = file->private_data; ret = stm401_ms_data_buffer_read(ps_stm401, &tmp_buff); if (copy_to_user(buffer, &tmp_buff, sizeof(struct stm401_moto_sensor_data)) != 0) { dev_err(&ps_stm401->client->dev, "Copy error\n"); ret = 0; } return ret; } static unsigned int stm401_ms_poll(struct file *file, struct poll_table_struct *wait) { unsigned int mask = 0; struct stm401_data *ps_stm401 = file->private_data; poll_wait(file, &ps_stm401->stm401_ms_data_wq, wait); if (ps_stm401->stm401_ms_data_buffer_head != ps_stm401->stm401_ms_data_buffer_tail) mask = POLLIN | POLLRDNORM; return mask; } const struct file_operations stm401_ms_fops = { .owner = THIS_MODULE, .open = stm401_ms_open, .read = stm401_ms_read, .poll = stm401_ms_poll, };