nfc: changed pthread_mutex to qemu_mutex
[sdk/emulator/qemu.git] / tizen / src / hw / virtio / maru_virtio_nfc.c
1 /*
2  * Virtio NFC Device
3  *
4  * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved
5  *
6  * Contact:
7  *  Munkyu Im <munkyu.im@samsung.com>
8  *  YeongKyoon Lee <yeongkyoon.lee@samsung.com>
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
23  *
24  * Contributors:
25  * - S-Core Co., Ltd
26  *
27  */
28
29 #include <pthread.h>
30
31 #include "hw/maru_device_ids.h"
32 #include "maru_virtio_nfc.h"
33 #include "debug_ch.h"
34 #include "ecs/ecs.h"
35
36 MULTI_DEBUG_CHANNEL(qemu, nfc);
37
38 #define NFC_DEVICE_NAME "virtio-nfc"
39
40 enum {
41     IOTYPE_INPUT = 0,
42     IOTYPE_OUTPUT = 1
43 };
44
45
46 #ifndef min
47 #define min(a,b) ((a)<(b)?(a):(b))
48 #endif
49
50 VirtIONFC* vio_nfc;
51
52 typedef struct MsgInfo
53 {
54     nfc_msg_info info;
55     QTAILQ_ENTRY(MsgInfo) next;
56 }MsgInfo;
57
58 static QTAILQ_HEAD(MsgInfoRecvHead , MsgInfo) nfc_recv_msg_queue =
59 QTAILQ_HEAD_INITIALIZER(nfc_recv_msg_queue);
60
61 typedef struct NFCBuf {
62     VirtQueueElement elem;
63     QTAILQ_ENTRY(NFCBuf) next;
64 } NFCBuf;
65
66
67 static char nfc_data [NFC_MAX_BUF_SIZE] = {'0',};
68 static QemuMutex recv_buf_mutex;
69
70 static void send_nfc_data_to_ecs(const char* data)
71 {
72     type_length length = 0;
73     type_group group = 15;
74     type_action action = 0;
75     int buf_len = strlen(data);
76     int message_len =  buf_len + 14;
77
78     char* ecs_message = (char*) malloc(message_len + 1);
79     if (!ecs_message)
80         return;
81
82     memset(ecs_message, 0, message_len + 1);
83
84     length = (unsigned short) buf_len;
85     action = 0;
86
87     memcpy(ecs_message, MESSAGE_TYPE_NFC, 3);
88     memcpy(ecs_message + 10, &length, sizeof(unsigned short));
89     memcpy(ecs_message + 12, &group, sizeof(unsigned char));
90     memcpy(ecs_message + 13, &action, sizeof(unsigned char));
91     memcpy(ecs_message + 14, data, buf_len);
92
93     TRACE("ntf_to_injector- len: %d, group: %d, action: %d, data: %s\n", length, group, action, data);
94
95     send_device_ntf(ecs_message, message_len);
96
97     if (ecs_message)
98         free(ecs_message);
99 }
100
101 void get_nfc_data(void)
102 {
103     send_nfc_data_to_ecs(nfc_data);
104 }
105
106 bool send_to_nfc(unsigned char id, unsigned char type, const char* data, const uint32_t len)
107 {
108     if(vio_nfc == NULL) {
109         ERR("NFC is not initialized\n");
110         return false;
111     }
112
113     if (unlikely(!virtio_queue_ready(vio_nfc->rvq))) {
114         ERR("virtio queue is not ready\n");
115         return false;
116     }
117
118     MsgInfo* _msg = (MsgInfo*) malloc(sizeof(MsgInfo));
119     if (!_msg) {
120         return false;
121     }
122
123     if(len > NFC_MAX_BUF_SIZE) {
124         ERR("the length of data is longer than max buffer size");
125         free(_msg);
126         return false;
127     }
128
129     memset(&_msg->info, 0, sizeof(nfc_msg_info));
130
131     memcpy(_msg->info.buf, data, len);
132     _msg->info.use = len;
133     _msg->info.client_id = id;
134     _msg->info.client_type = type;
135
136     qemu_mutex_lock(&recv_buf_mutex);
137     strcpy(nfc_data, data);
138     QTAILQ_INSERT_TAIL(&nfc_recv_msg_queue, _msg, next);
139
140     qemu_mutex_unlock(&recv_buf_mutex);
141
142     qemu_bh_schedule(vio_nfc->bh);
143
144     return true;
145 }
146
147 static void flush_nfc_recv_queue(void)
148 {
149     int index;
150
151     if (unlikely(!virtio_queue_ready(vio_nfc->rvq))) {
152         INFO("virtio queue is not ready\n");
153         return;
154     }
155
156     if (unlikely(virtio_queue_empty(vio_nfc->rvq))) {
157         TRACE("virtqueue is empty\n");
158         return;
159     }
160
161
162     qemu_mutex_lock(&recv_buf_mutex);
163
164     while (!QTAILQ_EMPTY(&nfc_recv_msg_queue))
165     {
166         MsgInfo* msginfo = QTAILQ_FIRST(&nfc_recv_msg_queue);
167         if (!msginfo) {
168             break;
169         }
170
171         VirtQueueElement elem;
172         index = virtqueue_pop(vio_nfc->rvq, &elem);
173         if (index == 0)
174         {
175             //ERR("unexpected empty queue");
176             break;
177         }
178
179         INFO(">> virtqueue_pop. index: %d, out_num : %d, in_num : %d\n", index, elem.out_num, elem.in_num);
180
181         memcpy(elem.in_sg[0].iov_base, &msginfo->info, sizeof(struct nfc_msg_info));
182
183         INFO(">> send to guest use = %d, msg = %s, iov_len = %d \n",
184                 msginfo->info.use, msginfo->info.buf, elem.in_sg[0].iov_len);
185
186         virtqueue_push(vio_nfc->rvq, &elem, sizeof(nfc_msg_info));
187         virtio_notify(&vio_nfc->vdev, vio_nfc->rvq);
188
189         QTAILQ_REMOVE(&nfc_recv_msg_queue, msginfo, next);
190         if (msginfo)
191             free(msginfo);
192     }
193
194     qemu_mutex_unlock(&recv_buf_mutex);
195
196 }
197
198
199 static void virtio_nfc_recv(VirtIODevice *vdev, VirtQueue *vq)
200 {
201     flush_nfc_recv_queue();
202 }
203
204 static void virtio_nfc_send(VirtIODevice *vdev, VirtQueue *vq)
205 {
206     VirtIONFC *vnfc = (VirtIONFC *)vdev;
207     int index = 0;
208     struct nfc_msg_info _msg;
209
210     if (virtio_queue_empty(vnfc->svq)) {
211         INFO("<< virtqueue is empty.\n");
212         return;
213     }
214
215     VirtQueueElement elem;
216
217     while ((index = virtqueue_pop(vq, &elem))) {
218
219         INFO("<< virtqueue pop. index: %d, out_num : %d, in_num : %d\n", index,  elem.out_num, elem.in_num);
220
221         INFO("<< iov_len = %d\n", elem.out_sg[0].iov_len);
222
223         memset(&_msg, 0x00, sizeof(_msg));
224         memcpy(&_msg, elem.out_sg[0].iov_base, elem.out_sg[0].iov_len);
225
226         INFO("<< recv from guest len = %d, msg = %s \n", _msg.use, _msg.buf);
227         send_nfc_ntf(&_msg);
228
229     }
230
231     virtqueue_push(vq, &elem, sizeof(VirtIONFC));
232     virtio_notify(&vio_nfc->vdev, vq);
233 }
234
235 static uint32_t virtio_nfc_get_features(VirtIODevice *vdev,
236         uint32_t request_feature)
237 {
238     TRACE("virtio_nfc_get_features.\n");
239     return 0;
240 }
241
242 static void maru_nfc_bh(void *opaque)
243 {
244     flush_nfc_recv_queue();
245 }
246
247 static void virtio_nfc_realize(DeviceState* dev, Error **errp)
248 {
249     VirtIODevice *vdev = VIRTIO_DEVICE(dev);
250     vio_nfc = VIRTIO_NFC(vdev);
251     if (vio_nfc == NULL) {
252         ERR("failed to initialize nfc device\n");
253         return;
254     }
255
256     INFO("initialize nfc device\n");
257
258     virtio_init(vdev, NFC_DEVICE_NAME, VIRTIO_ID_NFC, 0);
259
260     vio_nfc->rvq = virtio_add_queue(&vio_nfc->vdev, 256, virtio_nfc_recv);
261     vio_nfc->svq = virtio_add_queue(&vio_nfc->vdev, 256, virtio_nfc_send);
262
263     vio_nfc->bh = qemu_bh_new(maru_nfc_bh, vio_nfc);
264
265     qemu_mutex_init(&recv_buf_mutex);
266 }
267
268 static void virtio_nfc_unrealize(DeviceState* dev, Error **errp)
269 {
270     VirtIODevice *vdev = VIRTIO_DEVICE(dev);
271
272     INFO("destroy nfc device\n");
273
274     qemu_mutex_destroy(&recv_buf_mutex);
275
276     if (vio_nfc->bh) {
277         qemu_bh_delete(vio_nfc->bh);
278     }
279
280     virtio_cleanup(vdev);
281 }
282
283 static void virtio_nfc_reset(VirtIODevice *vdev)
284 {
285     TRACE("virtio_sensor_reset.\n");
286 }
287
288
289 static void virtio_nfc_class_init(ObjectClass *klass, void *data)
290 {
291     VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
292     vdc->realize = virtio_nfc_realize;
293     vdc->unrealize = virtio_nfc_unrealize;
294     vdc->get_features = virtio_nfc_get_features;
295     vdc->reset = virtio_nfc_reset;
296 }
297
298 static const TypeInfo virtio_device_info = {
299     .name = TYPE_VIRTIO_NFC,
300     .parent = TYPE_VIRTIO_DEVICE,
301     .instance_size = sizeof(VirtIONFC),
302     .class_init = virtio_nfc_class_init,
303 };
304
305 static void virtio_register_types(void)
306 {
307     type_register_static(&virtio_device_info);
308 }
309
310 type_init(virtio_register_types)
311