summaryrefslogtreecommitdiff
path: root/src/blt_b2r2.c
blob: cb017383d9b0df1e6155a5bd1337ad042d8100d6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
/*
 * Copyright (C) ST-Ericsson AB 2009 - All rights reserved
 * Reproduction and Communication of this document is strictly prohibited
 * unless specifically authorized in writing by ST-Ericsson
 *
 * \file    blt_b2r2.c
 * \brief   Android driver for B2R2 hardware
 * \author  ST-Ericsson
 *
 */

#include <blt_api.h>

#include <sys/ioctl.h>
#include <fcntl.h>
#include <errno.h>
#include <pthread.h>
#include <poll.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <video/b2r2_blt.h>

#define LOG_TAG "libblt_hw"

#ifdef ANDROID
#  include <cutils/log.h>
#  define LOGE2(...) LOGE(__VA_ARGS__)
#  define LOGI2(...) LOGI(__VA_ARGS__)
#else
#  define LOGE(format) fprintf(stderr, LOG_TAG format "\n")
#  define LOGE2(format, ...) fprintf(stderr, LOG_TAG format "\n", __VA_ARGS__)
#  define LOGI(format) printf(LOG_TAG format "\n")
#  define LOGI2(format, ...) printf(LOG_TAG format "\n", __VA_ARGS__)
#endif

#define B2R2_BLT_DEV "/dev/b2r2_blt"

struct blt_b2r2_data {
    int fd;
    pthread_t callback_thread;
};

#define DATAS_START_SIZE 10
#define DATAS_GROW_SIZE 5
static struct blt_b2r2_data **datas = NULL;
static int data_count = 0;

static int grow_datas(void)
{
    struct blt_b2r2_data **new_datas = NULL;
    int new_data_count = data_count + DATAS_GROW_SIZE;

    new_datas = malloc(new_data_count*sizeof(*new_datas));
    if (new_datas == NULL) {
        LOGE("Out of memory!");
        errno = -ENOMEM;
        goto error;
    }

    memset(new_datas, 0, new_data_count*sizeof(*new_datas));
    memcpy(new_datas, datas, data_count*sizeof(*datas));

    free(datas);

    data_count = new_data_count;
    datas = new_datas;

    return 0;

error:
    return -1;
}

static int get_handle(struct blt_b2r2_data *data) {
    int handle;

    if (datas == NULL) {

        datas = malloc(DATAS_START_SIZE*sizeof(*datas));
        if (datas == NULL) {
            LOGE("Out of memory!\n");
            errno = -ENOMEM;
            goto error;
        }

        data_count = DATAS_START_SIZE;
        memset(datas, 0, data_count*sizeof(*datas));
    }

    for (handle = 0; handle < data_count; handle++) {
        if (datas[handle] == NULL) {
            datas[handle] = data;
            break;
        }

        if (handle == data_count - 1) {
            if (grow_datas() < 0)
                goto error;
        }
    }

    return handle;

error:
    return -1;
}

static struct blt_b2r2_data *get_data(int handle) {
    if (handle >= data_count || handle < 0)
        return NULL;
    else
        return datas[handle];
}

static void free_handle(int handle) {
    if (handle < data_count && handle >= 0) {
        datas[handle] = NULL;
    }
}

static void *callback_thread_run(void *arg)
{
    /*
     * The resources consumed by this thread will be freed immediately when
     * this thread is terminated
     */
    pthread_detach(pthread_self());

    while (1) {
        int result;
        struct pollfd fds;
        struct b2r2_blt_report report;

        fds.fd = (int)arg;
        fds.events = POLLIN;

        result = poll(&fds, 1, 3000);
        switch (result) {
            case 0:
                /* timeout occurred */
                pthread_exit(NULL);
                break;
            case -1:
                /* We assume that this is because the device was closed */
                LOGE2("poll returned (%s)",
                        strerror(errno));
                pthread_exit(NULL);
                break;
            default:
                if (fds.revents & POLLIN) {
                    ssize_t count;
                    memset(&report, 0, sizeof(report));
                    count = read(fds.fd, &report, sizeof(report));
                    if (count < 0) {
                        LOGE2("Could not read report from b2r2 device (%s)",
                                strerror(errno));
                    } else if (report.report1 != 0) {
                        void (*callback)(int, uint32_t) = (void*)report.report1;
                        callback(report.request_id, (uint32_t)report.report2);
                    }
                } else if (fds.revents & POLLNVAL) {
                    /* fd not open, device must have been closed */
                    LOGI("Device closed. Callback thread terminated.\n");
                    pthread_exit(NULL);
                } else {
                    LOGE2("Unexpected event. Callback thread will exit. "
                        "errno=(%s) result=%d revents=0x%x",
                        strerror(errno), result, fds.revents);
                    pthread_exit(NULL);
                }
                break;
        }
    }
    return NULL;
}

int blt_open(void)
{
    struct blt_b2r2_data *data = NULL;
    int fd;
    int handle;

    fd = open(B2R2_BLT_DEV, O_RDWR);
    if (fd < 0) {
        LOGE2("Could not open device %s", B2R2_BLT_DEV);
        goto error;
    }

    data = malloc(sizeof(struct blt_b2r2_data));
    if (data == NULL) {
        LOGE("Out of memory");
        goto error;
    }

    memset(data, 0, sizeof(*data));

    data->fd = fd;
    data->callback_thread = -1;

    handle = get_handle(data);
    if (handle < 0)
        goto error_free;

    LOGI2("Library opened (handle = %d)", handle);

    return handle;

error_free:
    free(data);
error:
    return -1;
}

void blt_close(int blt_handle)
{
    struct blt_b2r2_data *data = get_data(blt_handle);

    if (data == NULL)
        goto out;

    close(data->fd);
    free_handle(blt_handle);
    free(data);

out:
    return;
}

int blt_request(int blt_handle, struct blt_req *req)
{
    struct blt_b2r2_data *data = get_data(blt_handle);
    int ret;

    if (data == NULL) {
        errno = EINVAL;
        ret = -1;
        goto out;
    }

    if (req->callback != NULL) {
        req->flags |= B2R2_BLT_FLAG_REPORT_WHEN_DONE;
#ifdef BLT_B2R2_DEBUG_PERFORMANCE
        req->flags |= B2R2_BLT_FLAG_REPORT_PERFORMANCE;
#endif

        if (data->callback_thread == -1) {
            /* Start a thread to wait for the requests to complete */
            pthread_create(&data->callback_thread, NULL, callback_thread_run,
                        (void *)data->fd);
        }
    }

    ret = ioctl(data->fd, B2R2_BLT_IOC, (struct b2r2_blt_req *) req);
    if (ret < 0)
        goto out;

out:
    return ret;
}

int blt_synch(int blt_handle, int request_id)
{
    struct blt_b2r2_data *data = get_data(blt_handle);

    if (data == NULL) {
        errno = EINVAL;
        return -1;
    }

    return ioctl(data->fd, B2R2_BLT_SYNCH_IOC, request_id);
}

int blt_query_cap(int blt_handle,
		enum blt_fmt fmt,
		enum blt_cap capability,
		uint32_t *cap)
{
    LOGE("blt_query_cap not implemented yet");
    errno = ENOSYS;
    return -1;
}