void ssp_sensorhub_report_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, NOTICE, notice); input_sync(hub_data->sensorhub_input_dev); if (notice == MSG2SSP_AP_STATUS_WAKEUP) sensorhub_info("wake up"); else if (notice == MSG2SSP_AP_STATUS_SLEEP) sensorhub_info("sleep"); else if (notice == MSG2SSP_AP_STATUS_RESET) sensorhub_info("reset"); else sensorhub_err("invalid notice(0x%x)", notice); }
void ssp_send_big_library_task(struct work_struct *work) { struct ssp_big *big = container_of(work, struct ssp_big, work); struct ssp_sensorhub_data *hub_data = big->data->hub_data; struct ssp_msg *msg; int buf_len, residue = big->length, ret = 0, index = 0, pos = 0; while (residue > 0) { buf_len = residue > DATA_PACKET_SIZE ? DATA_PACKET_SIZE : residue; msg = kzalloc(sizeof(*msg), GFP_KERNEL); msg->cmd = MSG2SSP_AP_SET_BIG_DATA; msg->length = buf_len; msg->options = AP2HUB_WRITE | (index++ << SSP_INDEX); msg->data = big->addr; msg->buffer = hub_data->big_send_events.library_data + pos; msg->free_buffer = 0; ret = ssp_spi_sync(big->data, msg, 1000); if (ret != SUCCESS) { sensorhub_err("send big data err(%d)", ret); return; } pos += buf_len; residue -= buf_len; sensorhub_info("send big data (%5d / %5d)", pos, big->length); } complete(&hub_data->big_write_done); }
static ssize_t ssp_sensorhub_read(struct file *file, 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); struct sensorhub_event *event; int retries = MAX_DATA_COPY_TRY; int length = 0; int ret = 0; spin_lock_bh(&hub_data->sensorhub_lock); if (unlikely(kfifo_is_empty(&hub_data->fifo))) { sensorhub_info("no library data"); goto err; } /* first in first out */ ret = kfifo_out_peek(&hub_data->fifo, &event, sizeof(void *)); if (unlikely(!ret)) { sensorhub_err("kfifo out peek err(%d)", ret); ret = EIO; goto err; } length = event->library_length; while (retries--) { ret = copy_to_user(buf, event->library_data, event->library_length); if (likely(!ret)) break; } if (unlikely(ret)) { sensorhub_err("read library data err(%d)", ret); goto err; } ssp_sensorhub_log(__func__, event->library_data, event->library_length); /* remove first event from the list */ ret = kfifo_out(&hub_data->fifo, &event, sizeof(void *)); if (unlikely(ret != sizeof(void *))) { sensorhub_err("kfifo out err(%d)", ret); ret = EIO; goto err; } complete(&hub_data->read_done); spin_unlock_bh(&hub_data->sensorhub_lock); return length; err: spin_unlock_bh(&hub_data->sensorhub_lock); return ret ? -ret : 0; }
static long ssp_sensorhub_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct ssp_sensorhub_data *hub_data = container_of(file->private_data, struct ssp_sensorhub_data, sensorhub_device); void __user *argp = (void __user *)arg; int retries = MAX_DATA_COPY_TRY; int length = 0; int ret = 0; switch (cmd) { case IOCTL_READ_BIG_CONTEXT_DATA: mutex_lock(&hub_data->big_events_lock); length = hub_data->big_events.library_length; if (unlikely(!hub_data->big_events.library_data || !hub_data->big_events.library_length)) { sensorhub_info("no big library data"); mutex_unlock(&hub_data->big_events_lock); return 0; } while (retries--) { ret = copy_to_user(argp, hub_data->big_events.library_data, hub_data->big_events.library_length); if (likely(!ret)) break; } if (unlikely(ret)) { sensorhub_err("read big library data err(%d)", ret); mutex_unlock(&hub_data->big_events_lock); return -ret; } ssp_sensorhub_log(__func__, hub_data->big_events.library_data, hub_data->big_events.library_length); hub_data->is_big_event = false; kfree(hub_data->big_events.library_data); hub_data->big_events.library_data = NULL; hub_data->big_events.library_length = 0; complete(&hub_data->big_read_done); mutex_unlock(&hub_data->big_events_lock); break; default: sensorhub_err("ioctl cmd err(%d)", cmd); return -EINVAL; } return length; }
static int ssp_sensorhub_list(struct ssp_sensorhub_data *hub_data, char *dataframe, int length) { struct sensorhub_event *event; int ret = 0; if (unlikely(length <= 0 || length >= PAGE_SIZE)) { sensorhub_err("library length err(%d)", length); return -EINVAL; } ssp_sensorhub_log(__func__, dataframe, length); /* overwrite new event if list is full */ if (unlikely(kfifo_is_full(&hub_data->fifo))) { ret = kfifo_out(&hub_data->fifo, &event, sizeof(void *)); if (unlikely(ret != sizeof(void *))) { sensorhub_err("kfifo out err(%d)", ret); return -EIO; } sensorhub_info("overwrite event"); } /* allocate memory for new event */ kfree(hub_data->events[hub_data->event_number].library_data); hub_data->events[hub_data->event_number].library_data = kzalloc(length * sizeof(char), GFP_ATOMIC); if (unlikely(!hub_data->events[hub_data->event_number].library_data)) { sensorhub_err("allocate memory for library err"); return -ENOMEM; } /* copy new event into memory */ memcpy(hub_data->events[hub_data->event_number].library_data, dataframe, length); hub_data->events[hub_data->event_number].library_length = length; /* add new event into the end of list */ event = &hub_data->events[hub_data->event_number]; ret = kfifo_in(&hub_data->fifo, &event, sizeof(void *)); if (unlikely(ret != sizeof(void *))) { sensorhub_err("kfifo in err(%d)", ret); return -EIO; } /* not to overflow max list capacity */ if (hub_data->event_number++ >= LIST_SIZE - 1) hub_data->event_number = 0; return kfifo_len(&hub_data->fifo) / sizeof(void *); }
static int ssp_sensorhub_thread(void *arg) { struct ssp_sensorhub_data *hub_data = (struct ssp_sensorhub_data *)arg; int ret = 0; while (likely(!kthread_should_stop())) { /* run thread if list is not empty */ wait_event_interruptible(hub_data->sensorhub_wq, kthread_should_stop() || !kfifo_is_empty(&hub_data->fifo) || hub_data->is_big_event); /* exit thread if kthread should stop */ if (unlikely(kthread_should_stop())) { sensorhub_info("kthread_stop()"); break; } if (likely(!kfifo_is_empty(&hub_data->fifo))) { /* report sensorhub event to user */ ssp_sensorhub_report_library(hub_data); /* wait until transfer finished */ ret = wait_for_completion_timeout( &hub_data->read_done, COMPLETION_TIMEOUT); if (unlikely(!ret)) sensorhub_err("wait for read timed out"); else if (unlikely(ret < 0)) sensorhub_err("read completion err(%d)", ret); } if (unlikely(hub_data->is_big_event)) { /* report big sensorhub event to user */ ssp_sensorhub_report_big_library(hub_data); /* wait until transfer finished */ ret = wait_for_completion_timeout( &hub_data->big_read_done, COMPLETION_TIMEOUT); if (unlikely(!ret)) sensorhub_err("wait for big read timed out"); else if (unlikely(ret < 0)) sensorhub_err("big read completion err(%d)", ret); } } return 0; }
void ssp_read_big_library_task(struct work_struct *work) { struct ssp_big *big = container_of(work, struct ssp_big, work); struct ssp_sensorhub_data *hub_data = big->data->hub_data; struct ssp_msg *msg; int buf_len, residue, ret = 0, index = 0, pos = 0; mutex_lock(&hub_data->big_events_lock); if (hub_data->big_events.library_data) kfree(hub_data->big_events.library_data); residue = big->length; hub_data->big_events.library_length = big->length; hub_data->big_events.library_data = kzalloc(big->length, GFP_ATOMIC); while (residue > 0) { buf_len = residue > DATA_PACKET_SIZE ? DATA_PACKET_SIZE : residue; msg = kzalloc(sizeof(*msg), GFP_ATOMIC); msg->cmd = MSG2SSP_AP_GET_BIG_DATA; msg->length = buf_len; msg->options = AP2HUB_READ | (index++ << SSP_INDEX); msg->data = big->addr; msg->buffer = hub_data->big_events.library_data + pos; msg->free_buffer = 0; ret = ssp_spi_sync(big->data, msg, 1000); if (ret != SUCCESS) { sensorhub_err("read big data err(%d)", ret); break; } pos += buf_len; residue -= buf_len; sensorhub_info("read big data (%5d / %5d)", pos, big->length); } hub_data->is_big_event = true; wake_up(&hub_data->sensorhub_wq); kfree(big); mutex_unlock(&hub_data->big_events_lock); }
void ssp_pcm_dump_task(struct work_struct *work) { struct ssp_big *big = container_of(work, struct ssp_big, work); struct ssp_sensorhub_data *hub_data = big->data->hub_data; struct ssp_msg *msg; int buf_len, residue = big->length, ret = 0, index = 0; mm_segment_t old_fs; struct file *voice_filp; char pcm_path[BIN_PATH_SIZE+1]; char *buff; old_fs = get_fs(); set_fs(KERNEL_DS); snprintf(pcm_path, BIN_PATH_SIZE, "/data/voice%d.pcm", hub_data->pcm_cnt); voice_filp = filp_open(pcm_path, O_RDWR | O_CREAT | O_APPEND, 0666); if (IS_ERR(voice_filp)) { sensorhub_err("open pcm dump file err"); goto exit; } buf_len = big->length > DATA_PACKET_SIZE ? DATA_PACKET_SIZE : big->length; buff = kzalloc(buf_len, GFP_KERNEL); while (residue > 0) { buf_len = residue > DATA_PACKET_SIZE ? DATA_PACKET_SIZE : residue; msg = kzalloc(sizeof(*msg), GFP_KERNEL); msg->cmd = MSG2SSP_AP_GET_BIG_DATA; msg->length = buf_len; msg->options = AP2HUB_READ | (index++ << SSP_INDEX); msg->data = big->addr; msg->buffer = buff; msg->free_buffer = 0; ret = ssp_spi_sync(big->data, msg, 1000); if (ret != SUCCESS) { sensorhub_err("receive pcm dump err(%d)", ret); break; } ret = voice_filp->f_op->write(voice_filp, (char __user *)buff, buf_len, &voice_filp->f_pos); if (ret < 0) { sensorhub_err("write pcm dump to file err(%d)", ret); break; } residue -= buf_len; sensorhub_info("write pcm dump..."); } filp_close(voice_filp, current->files); kfree(buff); exit: set_fs(old_fs); }