d986cbe775b00468faabff21f32f4b3a59f27e96
[project/umbim.git] / mbim-dev.c
1 /*
2 * umbim
3 * Copyright (C) 2014 John Crispin <blogic@openwrt.org>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2
7 * as published by the Free Software Foundation
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 */
14
15 #include <sys/types.h>
16 #include <sys/stat.h>
17
18 #include <fcntl.h>
19 #include <unistd.h>
20 #include <stdlib.h>
21 #include <stdio.h>
22 #include <stdint.h>
23
24 #include <libubox/uloop.h>
25
26 #include "mbim.h"
27
28 uint8_t mbim_buffer[MBIM_BUFFER_SIZE];
29 static struct uloop_fd mbim_fd;
30 static uint32_t expected;
31 int no_close;
32
33 static void mbim_msg_tout_cb(struct uloop_timeout *t)
34 {
35 fprintf(stderr, "ERROR: mbim message timeout\n");
36 uloop_end();
37 }
38
39 static struct uloop_timeout tout = {
40 .cb = mbim_msg_tout_cb,
41 };
42
43 int
44 mbim_send(void)
45 {
46 struct mbim_message_header *hdr = (struct mbim_message_header *) mbim_buffer;
47 int ret = 0;
48
49 if (le32toh(hdr->length) > MBIM_BUFFER_SIZE) {
50 fprintf(stderr, "message too big %d\n", le32toh(hdr->length));
51 return -1;
52 }
53
54 if (verbose) {
55 fprintf(stderr, "sending (%d): ", le32toh(hdr->length));
56 for (ret = 0; ret < le32toh(hdr->length); ret++)
57 printf("%02x ", ((uint8_t *) mbim_buffer)[ret]);
58 printf("\n");
59 printf(" header_type: %04X\n", le32toh(hdr->type));
60 printf(" header_length: %04X\n", le32toh(hdr->length));
61 printf(" header_transaction: %04X\n", le32toh(hdr->transaction_id));
62 }
63
64 ret = write(mbim_fd.fd, mbim_buffer, le32toh(hdr->length));
65 if (!ret) {
66 perror("writing data failed: ");
67 } else {
68 expected = le32toh(hdr->type) | 0x80000000;
69 uloop_timeout_set(&tout, 15000);
70 }
71 return ret;
72 }
73
74 static void
75 mbim_recv(struct uloop_fd *u, unsigned int events)
76 {
77 ssize_t cnt = read(u->fd, mbim_buffer, MBIM_BUFFER_SIZE);
78 struct mbim_message_header *hdr = (struct mbim_message_header *) mbim_buffer;
79 struct command_done_message *msg = (struct command_done_message *) (hdr + 1);
80 int i;
81
82 if (cnt < 0)
83 return;
84
85 if (cnt < sizeof(struct mbim_message_header)) {
86 perror("failed to read() data: ");
87 return;
88 }
89 if (verbose) {
90 printf("reading (%zu): ", cnt);
91 for (i = 0; i < cnt; i++)
92 printf("%02x ", mbim_buffer[i]);
93 printf("\n");
94 printf(" header_type: %04X\n", le32toh(hdr->type));
95 printf(" header_length: %04X\n", le32toh(hdr->length));
96 printf(" header_transaction: %04X\n", le32toh(hdr->transaction_id));
97 }
98
99 if (le32toh(hdr->type) == expected)
100 uloop_timeout_cancel(&tout);
101
102 switch(le32toh(hdr->type)) {
103 case MBIM_MESSAGE_TYPE_OPEN_DONE:
104 if (current_handler->request() < 0)
105 mbim_send_close_msg();
106 break;
107 case MBIM_MESSAGE_TYPE_COMMAND_DONE:
108 if (verbose) {
109 printf(" command_id: %04X\n", le32toh(msg->command_id));
110 printf(" status_code: %04X\n", le32toh(msg->status_code));
111 }
112 if (msg->status_code && !msg->buffer_length)
113 return_code = -le32toh(msg->status_code);
114 else
115 return_code = current_handler->response(msg->buffer, le32toh(msg->buffer_length));
116 if (return_code < 0)
117 no_close = 0;
118 mbim_send_close_msg();
119 break;
120 case MBIM_MESSAGE_TYPE_CLOSE_DONE:
121 uloop_end();
122 break;
123 case MBIM_MESSAGE_TYPE_FUNCTION_ERROR:
124 no_close = 0;
125 mbim_send_close_msg();
126 return_code = -1;
127 break;
128 }
129 }
130
131 void
132 mbim_open(const char *path)
133 {
134 mbim_fd.cb = mbim_recv;
135 mbim_fd.fd = open(path, O_RDWR);
136 if (mbim_fd.fd < 1) {
137 perror("open failed: ");
138 exit(-1);
139 }
140 uloop_fd_add(&mbim_fd, ULOOP_READ);
141 }