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;
}
예제 #4
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;
}
예제 #7
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);
}