293 lines
7.7 KiB
C
293 lines
7.7 KiB
C
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include <unistd.h>
|
|
#include <fcntl.h>
|
|
#include <pthread.h>
|
|
#include <sys/eventfd.h>
|
|
|
|
#include "dataserver_reader.h"
|
|
#include "dataserver_reader_inner.h"
|
|
|
|
#ifdef LOG_LOGCAT
|
|
|
|
#define LOG_TAG "ccdataserver"
|
|
#include <log/log.h>
|
|
#define ds_inf(_fmt_,...) ALOGI("%s:%d "_fmt_, __func__, __LINE__, ##__VA_ARGS__)
|
|
#define ds_err(_fmt_,...) ALOGE("%s:%d "_fmt_, __func__, __LINE__, ##__VA_ARGS__)
|
|
|
|
#else
|
|
|
|
#define ds_inf(_fmt_,...) printf("I %s:%d "_fmt_"\n", __func__, __LINE__, ##__VA_ARGS__)
|
|
#define ds_err(_fmt_,...) printf("E %s:%d "_fmt_"\n", __func__, __LINE__, ##__VA_ARGS__)
|
|
|
|
#endif
|
|
|
|
|
|
static struct list_head inst_list = LIST_HEAD_INIT(inst_list);
|
|
pthread_mutex_t inst_list_lock = PTHREAD_MUTEX_INITIALIZER;
|
|
|
|
static ds_reader_t* find_reader(const char *devname)
|
|
{
|
|
ds_reader_t *reader = NULL;
|
|
ds_reader_checker_t *checker;
|
|
|
|
for (checker = DS_READ_TASKS_CHECKER_START;
|
|
/*
|
|
* no "corrupt or misinterpret".
|
|
*/
|
|
/* coverity[ptr_arith] */
|
|
checker < DS_READ_TASKS_CHECKER_STOP; checker++) {
|
|
if ((reader = (*checker)(devname)))
|
|
break;
|
|
}
|
|
|
|
return reader;
|
|
}
|
|
|
|
/*
|
|
* return NULL if pushed successfully,
|
|
* return the callback if fail
|
|
*/
|
|
static ds_data_callback_t*
|
|
push_callback(reader_inst_t *inst, ds_data_callback_t *callback)
|
|
{
|
|
int callback_found = 0;
|
|
|
|
pthread_mutex_lock(&inst->callback_list_lock);
|
|
|
|
/*same (callback_fn + callback_priv) will be added only once*/
|
|
{
|
|
ds_data_callback_t *cb;
|
|
list_for_each_entry(cb, &inst->callback_list, head) {
|
|
if (cb->fn.data_cb == callback->fn.data_cb && cb->priv == callback->priv) {
|
|
callback_found = 1;
|
|
break;
|
|
}
|
|
}
|
|
if (!callback_found) {
|
|
list_for_each_entry(cb, &inst->callback_wait_list, head) {
|
|
if (cb->fn.data_cb == callback->fn.data_cb && cb->priv == callback->priv) {
|
|
callback_found = 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!callback_found)
|
|
list_add_tail(&callback->head, &inst->callback_wait_list);
|
|
|
|
pthread_mutex_unlock(&inst->callback_list_lock);
|
|
|
|
return callback_found? callback : NULL;
|
|
}
|
|
|
|
int ds_reader_start(const char *devname, const char *settings,
|
|
ds_data_callback_fn_t *data_callback, void *callback_priv)
|
|
{
|
|
reader_inst_t *inst = NULL;
|
|
int inst_new = 1;
|
|
int inst_ready = 0;
|
|
|
|
ds_inf("dev[%s], cb[%p:%p]", devname? devname:"null", data_callback, callback_priv);
|
|
|
|
if (!devname || !data_callback || !data_callback->data_cb) {
|
|
ds_err("incorrect parameter");
|
|
return -1;
|
|
}
|
|
|
|
/*create the callback node*/
|
|
ds_data_callback_t *callback =
|
|
(ds_data_callback_t *)calloc(1, sizeof(ds_data_callback_t));
|
|
|
|
if (callback) {
|
|
callback->fn = *data_callback;
|
|
callback->priv = callback_priv;
|
|
} else {
|
|
ds_err("no memory");
|
|
return -1;
|
|
}
|
|
|
|
/*make the callback running*/
|
|
|
|
pthread_mutex_lock(&inst_list_lock);
|
|
|
|
/*look for the inst(devname)*/
|
|
list_for_each_entry(inst, &inst_list, head) {
|
|
if (strcmp(inst->devname, devname) == 0) {
|
|
inst_new = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (inst_new) {
|
|
|
|
/*inst(devname) not exists, start new*/
|
|
|
|
inst = (reader_inst_t *)calloc(1, sizeof(reader_inst_t));
|
|
|
|
if (inst) {
|
|
inst->fd = open(devname, O_RDWR);
|
|
|
|
if (inst->fd >= 0) {
|
|
|
|
ds_reader_t *reader = find_reader(devname);
|
|
if (reader) {
|
|
|
|
if (reader->set)
|
|
reader->set(inst, settings);
|
|
|
|
inst->read_task = reader->task;
|
|
|
|
strncpy(inst->devname, devname, MAX_SIZE_DEVNAME);
|
|
inst->devname[MAX_SIZE_DEVNAME - 1] = '\0';
|
|
|
|
INIT_LIST_HEAD(&inst->callback_list);
|
|
INIT_LIST_HEAD(&inst->callback_wait_list);
|
|
|
|
pthread_mutex_init(&inst->callback_list_lock, NULL);
|
|
|
|
push_callback(inst, callback);
|
|
|
|
inst->running = 1;
|
|
inst->evtfd = eventfd(0, 0);
|
|
|
|
pthread_create(&inst->thread, NULL, inst->read_task, inst);
|
|
|
|
/*link the new inst*/
|
|
list_add_tail(&inst->head, &inst_list);
|
|
|
|
inst_ready = 1;
|
|
|
|
ds_inf("reader[%s] not found, new started", devname);
|
|
|
|
} else {
|
|
close(inst->fd);
|
|
free(inst);
|
|
|
|
ds_err("device[%s] is not supported yet", devname);
|
|
}
|
|
|
|
} else {
|
|
free(inst);
|
|
|
|
ds_err("can not open device[%s], err(%d:%s)",
|
|
devname, errno, strerror(errno));
|
|
}
|
|
|
|
} else {
|
|
ds_err("no memory");
|
|
}
|
|
|
|
} else {
|
|
|
|
int callback_found = 0;
|
|
|
|
/*inst(devname) exists, just add callback to the inst*/
|
|
|
|
ds_data_callback_t *cb = push_callback(inst, callback);
|
|
|
|
callback_found = cb? 1 : 0;
|
|
|
|
if (callback_found)
|
|
free(callback);
|
|
|
|
inst_ready = 1;
|
|
|
|
ds_inf("reader[%s] found, data callback (%s)",
|
|
devname, callback_found? "found" : "added");
|
|
}
|
|
|
|
pthread_mutex_unlock(&inst_list_lock);
|
|
|
|
if (!inst_ready)
|
|
free(callback);
|
|
|
|
return inst_ready? 0 : -1;
|
|
}
|
|
|
|
int ds_reader_stop(char *devname,
|
|
ds_data_callback_fn_t *data_callback, void *callback_priv)
|
|
{
|
|
reader_inst_t *inst = NULL;
|
|
int inst_found = 0;
|
|
|
|
pthread_mutex_lock(&inst_list_lock);
|
|
|
|
ds_inf("dev[%s], cb[%p:%p]", devname, data_callback, callback_priv);
|
|
|
|
/*look for the inst(devname)*/
|
|
list_for_each_entry(inst, &inst_list, head) {
|
|
if (strcmp(inst->devname, devname) == 0) {
|
|
inst_found = 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (inst_found) {
|
|
int callback_lists_all_empty = 0;
|
|
|
|
pthread_mutex_lock(&inst->callback_list_lock);
|
|
|
|
/*remove the callbacks from the inst*/
|
|
ds_data_callback_t *cb, *cb_tmp;
|
|
list_for_each_entry_safe(cb, cb_tmp, &inst->callback_list, head) {
|
|
if (cb->fn.data_cb == data_callback->data_cb && cb->priv == callback_priv) {
|
|
list_del(&cb->head);
|
|
free(cb);
|
|
|
|
ds_inf("reader[%s] found, data callback removed", devname);
|
|
break;
|
|
}
|
|
}
|
|
list_for_each_entry_safe(cb, cb_tmp, &inst->callback_wait_list, head) {
|
|
if (cb->fn.data_cb == data_callback->data_cb && cb->priv == callback_priv) {
|
|
list_del(&cb->head);
|
|
free(cb);
|
|
|
|
ds_inf("reader[%s] found, data callback(waiting) removed", devname);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (list_empty(&inst->callback_list) && list_empty(&inst->callback_wait_list))
|
|
callback_lists_all_empty = 1;
|
|
|
|
pthread_mutex_unlock(&inst->callback_list_lock);
|
|
|
|
/*if no callback in the inst, stop the inst*/
|
|
if (callback_lists_all_empty) {
|
|
|
|
list_del(&inst->head);
|
|
|
|
inst->running = 0;
|
|
{
|
|
int64_t pad = 1;
|
|
write(inst->evtfd, &pad, sizeof(pad));
|
|
}
|
|
|
|
|
|
pthread_join(inst->thread, NULL);
|
|
|
|
ds_reader_t *reader = find_reader(inst->devname);
|
|
if (reader && reader->close)
|
|
reader->close(inst);
|
|
|
|
close(inst->fd);
|
|
close(inst->evtfd);
|
|
|
|
free(inst);
|
|
|
|
ds_inf("reader[%s] stopped, due to no callback", devname);
|
|
}
|
|
}
|
|
|
|
pthread_mutex_unlock(&inst_list_lock);
|
|
|
|
return 0;
|
|
}
|
|
|