blob: 62bc40241b51ddd70639aab80985368b718f2fc4 [file] [log] [blame]
Harald Welte63653742019-01-03 16:54:16 +01001
Harald Weltee73a1df2019-05-15 22:27:02 +02002#include <errno.h>
Harald Welte63653742019-01-03 16:54:16 +01003#include <stdint.h>
4#include <endian.h>
5#include <sys/types.h>
6#include <linux/usb/functionfs.h>
7
8#include "ccid_proto.h"
9
Harald Welte63653742019-01-03 16:54:16 +010010#if __BYTE_ORDER == __LITTLE_ENDIAN
11#define cpu_to_le16(x) (x)
12#define cpu_to_le32(x) (x)
13#else
14#define cpu_to_le16(x) ((((x) >> 8) & 0xffu) | (((x) & 0xffu) << 8))
15#define cpu_to_le32(x) \
16 ((((x) & 0xff000000u) >> 24) | (((x) & 0x00ff0000u) >> 8) | \
17 (((x) & 0x0000ff00u) << 8) | (((x) & 0x000000ffu) << 24))
18#endif
19
20#define le32_to_cpu(x) le32toh(x)
21#define le16_to_cpu(x) le16toh(x)
22
23/***********************************************************************
24 * Actual USB CCID Descriptors
25 ***********************************************************************/
26
27static const struct {
28 struct usb_functionfs_descs_head_v2 header;
29 __le32 fs_count;
30 struct {
31 struct usb_interface_descriptor intf;
32 struct usb_ccid_class_descriptor ccid;
33 struct usb_endpoint_descriptor_no_audio ep_irq;
34 struct usb_endpoint_descriptor_no_audio ep_out;
35 struct usb_endpoint_descriptor_no_audio ep_in;
36 } __attribute__ ((packed)) fs_descs;
37} __attribute__ ((packed)) descriptors = {
38 .header = {
39 .magic = cpu_to_le32(FUNCTIONFS_DESCRIPTORS_MAGIC_V2),
40 .flags = cpu_to_le32(FUNCTIONFS_HAS_FS_DESC),
41 .length = cpu_to_le32(sizeof(descriptors)),
42 },
43 .fs_count = cpu_to_le32(5),
44 .fs_descs = {
45 .intf = {
46 .bLength = sizeof(descriptors.fs_descs.intf),
47 .bDescriptorType = USB_DT_INTERFACE,
48 .bNumEndpoints = 3,
49 .bInterfaceClass = 11,
50 .iInterface = 1,
51 },
52 .ccid = {
53 .bLength = sizeof(descriptors.fs_descs.ccid),
54 .bDescriptorType = 33,
55 .bcdCCID = cpu_to_le16(0x0110),
56 .bMaxSlotIndex = 7,
57 .bVoltageSupport = 0x07, /* 5/3/1.8V */
58 .dwProtocols = cpu_to_le32(1), /* T=0 only */
59 .dwDefaultClock = cpu_to_le32(5000),
60 .dwMaximumClock = cpu_to_le32(20000),
61 .bNumClockSupported = 0,
62 .dwDataRate = cpu_to_le32(9600),
63 .dwMaxDataRate = cpu_to_le32(921600),
64 .bNumDataRatesSupported = 0,
65 .dwMaxIFSD = cpu_to_le32(0),
66 .dwSynchProtocols = cpu_to_le32(0),
67 .dwMechanical = cpu_to_le32(0),
68 .dwFeatures = cpu_to_le32(0x10),
69 .dwMaxCCIDMessageLength = 272,
70 .bClassGetResponse = 0xff,
71 .bClassEnvelope = 0xff,
72 .wLcdLayout = cpu_to_le16(0),
73 .bPINSupport = 0,
74 .bMaxCCIDBusySlots = 8,
75 },
76 .ep_irq = {
77 .bLength = sizeof(descriptors.fs_descs.ep_irq),
78 .bDescriptorType = USB_DT_ENDPOINT,
79 .bEndpointAddress = 1 | USB_DIR_IN,
80 .bmAttributes = USB_ENDPOINT_XFER_INT,
81 .wMaxPacketSize = 64,
82 },
83 .ep_out = {
84 .bLength = sizeof(descriptors.fs_descs.ep_out),
85 .bDescriptorType = USB_DT_ENDPOINT,
86 .bEndpointAddress = 2 | USB_DIR_OUT,
87 .bmAttributes = USB_ENDPOINT_XFER_BULK,
88 /* .wMaxPacketSize = autoconfiguration (kernel) */
89 },
90 .ep_in = {
91 .bLength = sizeof(descriptors.fs_descs.ep_in),
92 .bDescriptorType = USB_DT_ENDPOINT,
93 .bEndpointAddress = 3 | USB_DIR_IN,
94 .bmAttributes = USB_ENDPOINT_XFER_BULK,
95 /* .wMaxPacketSize = autoconfiguration (kernel) */
96 },
97 },
98};
99
100#define STR_INTERFACE_ "Osmocom CCID Interface"
101
102static const struct {
103 struct usb_functionfs_strings_head header;
104 struct {
105 __le16 code;
106 const char str1[sizeof(STR_INTERFACE_)];
107 } __attribute__((packed)) lang0;
108} __attribute__((packed)) strings = {
109 .header = {
110 .magic = cpu_to_le32(FUNCTIONFS_STRINGS_MAGIC),
111 .length = cpu_to_le32(sizeof(strings)),
112 .str_count = cpu_to_le32(1),
113 .lang_count = cpu_to_le32(1),
114 },
115 .lang0 = {
116 cpu_to_le16(0x0409), /* en-us */
117 STR_INTERFACE_,
118 },
119};
120
121
122
123/***********************************************************************
124 * USB FunctionFS interface
125 ***********************************************************************/
126
127#include <stdlib.h>
128#include <stdio.h>
129#include <unistd.h>
Harald Welte63976d42019-05-16 11:05:52 +0200130#include <string.h>
Harald Welte63653742019-01-03 16:54:16 +0100131#include <assert.h>
132#include <fcntl.h>
133#include <sys/stat.h>
134#include <osmocom/core/select.h>
135#include <osmocom/core/utils.h>
Harald Welted5d555c2019-05-15 19:53:24 +0200136#include <osmocom/core/msgb.h>
Harald Weltee73a1df2019-05-15 22:27:02 +0200137#include <osmocom/core/utils.h>
138#include <osmocom/core/application.h>
139#include <osmocom/core/logging.h>
Harald Welted5d555c2019-05-15 19:53:24 +0200140
141#include "ccid_device.h"
Harald Weltecab5d152019-05-16 13:31:16 +0200142#include "ccid_slot_sim.h"
Harald Welte63653742019-01-03 16:54:16 +0100143
144#ifndef FUNCTIONFS_SUPPORTS_POLL
145#include <libaio.h>
146struct aio_help {
Harald Welted5d555c2019-05-15 19:53:24 +0200147 struct msgb *msg;
Harald Welte63653742019-01-03 16:54:16 +0100148 struct iocb *iocb;
149};
150#endif
151
152/* usb function handle */
153struct ufunc_handle {
154 struct osmo_fd ep0;
155 struct osmo_fd ep_in;
156 struct osmo_fd ep_out;
157 struct osmo_fd ep_int;
Harald Welte63976d42019-05-16 11:05:52 +0200158 struct llist_head ep_in_queue;
159 struct llist_head ep_int_queue;
Harald Welte63653742019-01-03 16:54:16 +0100160#ifndef FUNCTIONFS_SUPPORTS_POLL
161 struct osmo_fd aio_evfd;
162 io_context_t aio_ctx;
163 struct aio_help aio_in;
164 struct aio_help aio_out;
165 struct aio_help aio_int;
166#endif
Harald Welted5d555c2019-05-15 19:53:24 +0200167 struct ccid_instance *ccid_handle;
Harald Welte63653742019-01-03 16:54:16 +0100168};
169
170static int ep_int_cb(struct osmo_fd *ofd, unsigned int what)
171{
Harald Weltee73a1df2019-05-15 22:27:02 +0200172 LOGP(DUSB, LOGL_DEBUG, "%s\n", __func__);
Harald Welte63653742019-01-03 16:54:16 +0100173 return 0;
174}
175
176static int ep_out_cb(struct osmo_fd *ofd, unsigned int what)
177{
Harald Welted5d555c2019-05-15 19:53:24 +0200178 struct ufunc_handle *uh = (struct ufunc_handle *) ofd->data;
179 struct msgb *msg = msgb_alloc(512, "OUT-Rx");
Harald Welte63653742019-01-03 16:54:16 +0100180 int rc;
181
Harald Weltee73a1df2019-05-15 22:27:02 +0200182 LOGP(DUSB, LOGL_DEBUG, "%s\n", __func__);
Harald Welte63653742019-01-03 16:54:16 +0100183 if (what & BSC_FD_READ) {
Harald Welted5d555c2019-05-15 19:53:24 +0200184 rc = read(ofd->fd, msgb_data(msg), msgb_tailroom(msg));
185 if (rc <= 0) {
186 msgb_free(msg);
187 return rc;
188 }
189 msgb_put(msg, rc);
190 ccid_handle_out(uh->ccid_handle, msg);
Harald Welte63653742019-01-03 16:54:16 +0100191 }
192 return 0;
193}
194
195static int ep_in_cb(struct osmo_fd *ofd, unsigned int what)
196{
Harald Weltee73a1df2019-05-15 22:27:02 +0200197 LOGP(DUSB, LOGL_DEBUG, "%s\n", __func__);
Harald Welte63653742019-01-03 16:54:16 +0100198 if (what & BSC_FD_WRITE) {
199 /* write what we have to write */
200 }
201 return 0;
202}
203
204const struct value_string ffs_evt_type_names[] = {
205 { FUNCTIONFS_BIND, "BIND" },
206 { FUNCTIONFS_UNBIND, "UNBIND" },
207 { FUNCTIONFS_ENABLE, "ENABLE" },
208 { FUNCTIONFS_DISABLE, "DISABLE" },
209 { FUNCTIONFS_SETUP, "SETUP" },
210 { FUNCTIONFS_SUSPEND, "SUSPEND" },
211 { FUNCTIONFS_RESUME, "RESUME" },
212 { 0, NULL }
213};
214
215static void handle_setup(const struct usb_ctrlrequest *setup)
216{
Harald Weltee73a1df2019-05-15 22:27:02 +0200217 LOGP(DUSB, LOGL_NOTICE, "EP0 SETUP bRequestType=0x%02x, bRequest=0x%02x wValue=0x%04x, "
218 "wIndex=0x%04x, wLength=%u\n", setup->bRequestType, setup->bRequest,
219 le16_to_cpu(setup->wValue), le16_to_cpu(setup->wIndex), le16_to_cpu(setup->wLength));
220 /* FIXME: Handle control transfer */
Harald Welte63653742019-01-03 16:54:16 +0100221}
222
223static void aio_refill_out(struct ufunc_handle *uh);
224
225static int ep_0_cb(struct osmo_fd *ofd, unsigned int what)
226{
227 struct ufunc_handle *uh = (struct ufunc_handle *) ofd->data;
228 int rc;
229
Harald Welte63653742019-01-03 16:54:16 +0100230 if (what & BSC_FD_READ) {
231 struct usb_functionfs_event evt;
232 rc = read(ofd->fd, (uint8_t *)&evt, sizeof(evt));
233 if (rc < sizeof(evt))
234 return -23;
Harald Weltee73a1df2019-05-15 22:27:02 +0200235 LOGP(DUSB, LOGL_NOTICE, "EP0 %s\n", get_value_string(ffs_evt_type_names, evt.type));
Harald Welte63653742019-01-03 16:54:16 +0100236 switch (evt.type) {
237 case FUNCTIONFS_ENABLE:
238 aio_refill_out(uh);
239 break;
240 case FUNCTIONFS_SETUP:
241 handle_setup(&evt.u.setup);
242 break;
243 }
244
245 }
246 return 0;
247}
248
249#ifndef FUNCTIONFS_SUPPORTS_POLL
250
Harald Welte63976d42019-05-16 11:05:52 +0200251/* an AIO read (OUT) has just completed, let's refill the transfer */
Harald Welte63653742019-01-03 16:54:16 +0100252static void aio_refill_out(struct ufunc_handle *uh)
253{
254 int rc;
255 struct aio_help *ah = &uh->aio_out;
Harald Weltee73a1df2019-05-15 22:27:02 +0200256
257 LOGP(DUSB, LOGL_DEBUG, "%s\n", __func__);
Harald Welte63976d42019-05-16 11:05:52 +0200258 OSMO_ASSERT(!ah->msg);
259 ah->msg = msgb_alloc(512, "OUT-Rx-AIO");
260 OSMO_ASSERT(ah->msg);
Harald Welted5d555c2019-05-15 19:53:24 +0200261 io_prep_pread(ah->iocb, uh->ep_out.fd, msgb_data(ah->msg), msgb_tailroom(ah->msg), 0);
Harald Welte63653742019-01-03 16:54:16 +0100262 io_set_eventfd(ah->iocb, uh->aio_evfd.fd);
263 rc = io_submit(uh->aio_ctx, 1, &ah->iocb);
264 OSMO_ASSERT(rc >= 0);
265}
266
Harald Welte63976d42019-05-16 11:05:52 +0200267/* dequeue the next msgb from ep_in_queue and set up AIO for it */
268static void dequeue_aio_write_in(struct ufunc_handle *uh)
269{
270 struct aio_help *ah = &uh->aio_in;
271 struct msgb *d;
272 int rc;
273
274 if (ah->msg)
275 return;
276
277 d = msgb_dequeue(&uh->ep_in_queue);
278 if (!d)
279 return;
280
281 OSMO_ASSERT(ah->iocb);
282 ah->msg = d;
283 io_prep_pwrite(ah->iocb, uh->ep_in.fd, msgb_data(d), msgb_length(d), 0);
284 io_set_eventfd(ah->iocb, uh->aio_evfd.fd);
285 rc = io_submit(uh->aio_ctx, 1, &ah->iocb);
286 OSMO_ASSERT(rc >= 0);
287
288}
289
290/* dequeue the next msgb from ep_int_queue and set up AIO for it */
291static void dequeue_aio_write_int(struct ufunc_handle *uh)
292{
293 struct aio_help *ah = &uh->aio_int;
294 struct msgb *d;
295 int rc;
296
297 if (ah->msg)
298 return;
299
300 d = msgb_dequeue(&uh->ep_int_queue);
301 if (!d)
302 return;
303
304 OSMO_ASSERT(ah->iocb);
305 ah->msg = d;
306 io_prep_pwrite(ah->iocb, uh->ep_int.fd, msgb_data(d), msgb_length(d), 0);
307 io_set_eventfd(ah->iocb, uh->aio_evfd.fd);
308 rc = io_submit(uh->aio_ctx, 1, &ah->iocb);
309 OSMO_ASSERT(rc >= 0);
310}
311
Harald Welte63653742019-01-03 16:54:16 +0100312static int evfd_cb(struct osmo_fd *ofd, unsigned int what)
313{
314 struct ufunc_handle *uh = (struct ufunc_handle *) ofd->data;
315 struct io_event evt[3];
Harald Welte63976d42019-05-16 11:05:52 +0200316 struct msgb *msg;
Harald Welte63653742019-01-03 16:54:16 +0100317 uint64_t ev_cnt;
318 int i, rc;
319
320 rc = read(ofd->fd, &ev_cnt, sizeof(ev_cnt));
321 assert(rc == sizeof(ev_cnt));
322
323 rc = io_getevents(uh->aio_ctx, 1, 3, evt, NULL);
Harald Weltee73a1df2019-05-15 22:27:02 +0200324 if (rc <= 0) {
325 LOGP(DUSB, LOGL_ERROR, "error in io_getevents(): %d\n", rc);
Harald Welte63653742019-01-03 16:54:16 +0100326 return rc;
Harald Weltee73a1df2019-05-15 22:27:02 +0200327 }
Harald Welte63653742019-01-03 16:54:16 +0100328
329 for (i = 0; i < rc; i++) {
330 int fd = evt[i].obj->aio_fildes;
331 if (fd == uh->ep_int.fd) {
332 /* interrupt endpoint AIO has completed. This means the IRQ transfer
333 * which we generated has reached the host */
Harald Weltee73a1df2019-05-15 22:27:02 +0200334 LOGP(DUSB, LOGL_DEBUG, "IRQ AIO completed, free()ing msgb\n");
Harald Weltea74fe0c2019-05-16 13:46:10 +0200335 msgb_free(uh->aio_int.msg);
336 uh->aio_int.msg = NULL;
Harald Welte63976d42019-05-16 11:05:52 +0200337 dequeue_aio_write_int(uh);
Harald Welte63653742019-01-03 16:54:16 +0100338 } else if (fd == uh->ep_in.fd) {
339 /* IN endpoint AIO has completed. This means the IN transfer which
340 * we sent to the host has completed */
Harald Weltee73a1df2019-05-15 22:27:02 +0200341 LOGP(DUSB, LOGL_DEBUG, "IN AIO completed, free()ing msgb\n");
Harald Weltebcbc1972019-05-15 21:57:32 +0200342 msgb_free(uh->aio_in.msg);
343 uh->aio_in.msg = NULL;
Harald Welte63976d42019-05-16 11:05:52 +0200344 dequeue_aio_write_in(uh);
Harald Welte63653742019-01-03 16:54:16 +0100345 } else if (fd == uh->ep_out.fd) {
Harald Weltee73a1df2019-05-15 22:27:02 +0200346 /* OUT endpoint AIO has completed. This means the host has sent us
Harald Welte63653742019-01-03 16:54:16 +0100347 * some OUT data */
Harald Weltee73a1df2019-05-15 22:27:02 +0200348 LOGP(DUSB, LOGL_DEBUG, "OUT AIO completed, dispatching received msg\n");
Harald Welted5d555c2019-05-15 19:53:24 +0200349 msgb_put(uh->aio_out.msg, evt[i].res);
Harald Weltee73a1df2019-05-15 22:27:02 +0200350 //printf("\t%s\n", msgb_hexdump(uh->aio_out.msg));
Harald Welte63976d42019-05-16 11:05:52 +0200351 msg = uh->aio_out.msg;
352 uh->aio_out.msg = NULL;
353 /* CCID handler takes ownership of msgb */
354 ccid_handle_out(uh->ccid_handle, msg);
Harald Welte63653742019-01-03 16:54:16 +0100355 aio_refill_out(uh);
356 }
357 }
Harald Weltebcbc1972019-05-15 21:57:32 +0200358 return 0;
Harald Welte63653742019-01-03 16:54:16 +0100359}
360#endif
361
362
363static int ep0_init(struct ufunc_handle *uh)
364{
365 int rc;
366
367 /* open control endpoint and write descriptors to it */
368 rc = open("ep0", O_RDWR);
369 assert(rc >= 0);
370 osmo_fd_setup(&uh->ep0, rc, BSC_FD_READ, &ep_0_cb, uh, 0);
371 osmo_fd_register(&uh->ep0);
372 rc = write(uh->ep0.fd, &descriptors, sizeof(descriptors));
Harald Weltee73a1df2019-05-15 22:27:02 +0200373 if (rc != sizeof(descriptors)) {
374 LOGP(DUSB, LOGL_ERROR, "Cannot write descriptors: %s\n", strerror(errno));
Harald Welte63653742019-01-03 16:54:16 +0100375 return -1;
Harald Weltee73a1df2019-05-15 22:27:02 +0200376 }
Harald Welte63653742019-01-03 16:54:16 +0100377 rc = write(uh->ep0.fd, &strings, sizeof(strings));
Harald Weltee73a1df2019-05-15 22:27:02 +0200378 if (rc != sizeof(strings)) {
379 LOGP(DUSB, LOGL_ERROR, "Cannot write strings: %s\n", strerror(errno));
Harald Welte63653742019-01-03 16:54:16 +0100380 return -1;
Harald Weltee73a1df2019-05-15 22:27:02 +0200381 }
Harald Welte63653742019-01-03 16:54:16 +0100382
383 /* open other endpoint file descriptors */
Harald Welte63976d42019-05-16 11:05:52 +0200384 INIT_LLIST_HEAD(&uh->ep_int_queue);
Harald Welte63653742019-01-03 16:54:16 +0100385 rc = open("ep1", O_RDWR);
386 assert(rc >= 0);
387 osmo_fd_setup(&uh->ep_int, rc, 0, &ep_int_cb, uh, 1);
388#ifdef FUNCTIONFS_SUPPORTS_POLL
389 osmo_fd_register(&uh->ep_int);
390#endif
391
392 rc = open("ep2", O_RDWR);
393 assert(rc >= 0);
394 osmo_fd_setup(&uh->ep_out, rc, BSC_FD_READ, &ep_out_cb, uh, 2);
395#ifdef FUNCTIONFS_SUPPORTS_POLL
396 osmo_fd_register(&uh->ep_out);
397#endif
398
Harald Welte63976d42019-05-16 11:05:52 +0200399 INIT_LLIST_HEAD(&uh->ep_in_queue);
Harald Welte63653742019-01-03 16:54:16 +0100400 rc = open("ep3", O_RDWR);
401 assert(rc >= 0);
402 osmo_fd_setup(&uh->ep_in, rc, 0, &ep_in_cb, uh, 3);
403#ifdef FUNCTIONFS_SUPPORTS_POLL
404 osmo_fd_register(&uh->ep_in);
405#endif
406
407#ifndef FUNCTIONFS_SUPPORTS_POLL
408#include <sys/eventfd.h>
409 /* for some absolutely weird reason, gadgetfs+functionfs don't support
410 * the standard methods of non-blocking I/o (select/poll). We need to
411 * work around using Linux AIO, which is not to be confused with POSIX AIO! */
412
413 memset(&uh->aio_ctx, 0, sizeof(uh->aio_ctx));
414 rc = io_setup(3, &uh->aio_ctx);
415 OSMO_ASSERT(rc >= 0);
416
417 /* create an eventfd, which will be marked readable once some AIO completes */
418 rc = eventfd(0, 0);
419 OSMO_ASSERT(rc >= 0);
420 osmo_fd_setup(&uh->aio_evfd, rc, BSC_FD_READ, &evfd_cb, uh, 0);
421 osmo_fd_register(&uh->aio_evfd);
422
Harald Welte63653742019-01-03 16:54:16 +0100423 uh->aio_out.iocb = malloc(sizeof(struct iocb));
Harald Welte63976d42019-05-16 11:05:52 +0200424 uh->aio_in.iocb = malloc(sizeof(struct iocb));
425 uh->aio_int.iocb = malloc(sizeof(struct iocb));
Harald Welte63653742019-01-03 16:54:16 +0100426#endif
427
428 return 0;
429}
430
Harald Weltebcbc1972019-05-15 21:57:32 +0200431static int ccid_ops_send_in(struct ccid_instance *ci, struct msgb *msg)
432{
433 struct ufunc_handle *uh = ci->priv;
Harald Weltebcbc1972019-05-15 21:57:32 +0200434
Harald Welte63976d42019-05-16 11:05:52 +0200435 /* append to the queue */
436 msgb_enqueue(&uh->ep_in_queue, msg);
Harald Weltebcbc1972019-05-15 21:57:32 +0200437
Harald Welte63976d42019-05-16 11:05:52 +0200438 /* trigger, if needed */
439#ifndef FUNCTIONFS_SUPPORTS_POLL
440 dequeue_aio_write_in(uh);
441#else
442 uh->ep_in.when |= BSC_FD_WRITE;
443#endif
444 return 0;
445}
446
447static int ccid_ops_send_int(struct ccid_instance *ci, struct msgb *msg)
448{
449 struct ufunc_handle *uh = ci->priv;
450
451 /* append to the queue */
452 msgb_enqueue(&uh->ep_int_queue, msg);
453
454 /* trigger, if needed */
455#ifndef FUNCTIONFS_SUPPORTS_POLL
456 dequeue_aio_write_int(uh);
457#else
458 uh->ep_int.when |= BSC_FD_WRITE;
459#endif
Harald Weltebcbc1972019-05-15 21:57:32 +0200460 return 0;
461}
462
463static const struct ccid_ops c_ops = {
464 .send_in = ccid_ops_send_in,
Harald Weltea7da5042019-05-16 11:08:35 +0200465 .send_int = ccid_ops_send_int,
Harald Weltebcbc1972019-05-15 21:57:32 +0200466};
Harald Welte63653742019-01-03 16:54:16 +0100467
Harald Weltee73a1df2019-05-15 22:27:02 +0200468static const struct log_info_cat log_info_cat[] = {
469 [DUSB] = {
470 .name = "USB",
471 .description = "USB Transport",
472 .enabled = 1,
473 .loglevel = LOGL_NOTICE,
474 },
475 [DCCID] = {
476 .name = "CCID",
477 .description = "CCID Core",
478 .color = "\033[1;35m",
479 .enabled = 1,
480 .loglevel = LOGL_DEBUG,
481 },
482};
483
484static const struct log_info log_info = {
485 .cat = log_info_cat,
486 .num_cat = ARRAY_SIZE(log_info_cat),
487};
488
489static void *tall_main_ctx;
490
Harald Welte824406d2019-05-16 11:15:53 +0200491static void signal_handler(int signal)
492{
493 switch (signal) {
494 case SIGUSR1:
495 talloc_report_full(tall_main_ctx, stderr);
496 break;
497 }
498}
499
500
Harald Welte63653742019-01-03 16:54:16 +0100501int main(int argc, char **argv)
502{
503 struct ufunc_handle ufh = (struct ufunc_handle) { 0, };
Harald Weltebcbc1972019-05-15 21:57:32 +0200504 struct ccid_instance ci = (struct ccid_instance) { 0, };
Harald Welte63653742019-01-03 16:54:16 +0100505 int rc;
506
Harald Weltee73a1df2019-05-15 22:27:02 +0200507 tall_main_ctx = talloc_named_const(NULL, 0, "ccid_main_functionfs");
508 msgb_talloc_ctx_init(tall_main_ctx, 0);
509 osmo_init_logging2(tall_main_ctx, &log_info);
510
Harald Welte824406d2019-05-16 11:15:53 +0200511 signal(SIGUSR1, &signal_handler);
512
Harald Weltecab5d152019-05-16 13:31:16 +0200513 ccid_instance_init(&ci, &c_ops, &slotsim_slot_ops, "", &ufh);
Harald Weltebcbc1972019-05-15 21:57:32 +0200514 ufh.ccid_handle = &ci;
515
Harald Weltee73a1df2019-05-15 22:27:02 +0200516 if (argc < 2) {
517 fprintf(stderr, "You have to specify the mount-path of the functionfs\n");
518 exit(2);
519 }
520
Harald Welte63653742019-01-03 16:54:16 +0100521 chdir(argv[1]);
522 rc = ep0_init(&ufh);
523 if (rc < 0) {
524 fprintf(stderr, "Error %d\n", rc);
Harald Weltee73a1df2019-05-15 22:27:02 +0200525 exit(1);
Harald Welte63653742019-01-03 16:54:16 +0100526 }
527
528 while (1) {
529 osmo_select_main(0);
530 }
531}