20c3ed626ee9388f7bd888964e5e7396142f640e
[hayes-ril.git] / device / gta04 / gta04.c
1 /*
2  * This file is part of hayes-ril.
3  *
4  * Copyright (C) 2012 Paul Kocialkowski <contact@paulk.fr>
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18
19 #include <stdlib.h>
20 #include <termios.h>
21 #include <unistd.h>
22 #include <fcntl.h>
23 #include <sys/stat.h>
24
25 #define LOG_TAG "RIL-DEV"
26 #include <utils/Log.h>
27
28 #include "gta04.h"
29 #include <hayes-ril.h>
30
31 int gta04_power_boot(void *sdata)
32 {
33         struct stat tty_node_stat;
34         char *tty_node;
35         int rc;
36         int i;
37
38         for(i=0 ; i < TTY_NODE_MAX ; i++) {
39                 asprintf(&tty_node, "%s/%s%d", TTY_DEV_BASE, TTY_NODE_BASE, i);
40
41                 rc = stat(tty_node, &tty_node_stat);
42                 if(rc < 0) {
43                         free(tty_node);
44                         return -1;
45                 }
46
47                 free(tty_node);
48         }
49
50         return 0;
51 }
52
53 int gta04_transport_sdata_create(void **sdata)
54 {
55         struct gta04_transport_data *transport_data = NULL;
56
57         transport_data = malloc(sizeof(struct gta04_transport_data));
58         memset(transport_data, 0, sizeof(struct gta04_transport_data));
59
60         *sdata = (void *) transport_data;
61
62         return 0;
63 }
64
65 int gta04_transport_sdata_destroy(void *sdata)
66 {
67         if(sdata == NULL)
68                 return 0;
69
70         free(sdata);
71
72         return 0;
73 }
74
75 int gta04_transport_find_node(char **tty_node, char *name)
76 {
77         char *tty_sysfs_node = NULL;
78         char *buf = NULL;
79         int name_length;
80         int fd = -1;
81         int i;
82
83         if(tty_node == NULL || name == NULL)
84                 return -1;
85
86         name_length = strlen(name);
87         buf = calloc(1, name_length);
88
89         for(i=0 ; i < TTY_NODE_MAX ; i++) {
90                 asprintf(&tty_sysfs_node, "%s/%s%d/%s",
91                         TTY_SYSFS_BASE, TTY_NODE_BASE, i, TTY_HSOTYPE);
92
93                 fd = open(tty_sysfs_node, O_RDONLY);
94                 if(fd < 0) {
95                         free(tty_sysfs_node);
96                         continue;
97                 }
98
99                 read(fd, buf, name_length);
100                 if(strncmp(name, buf, name_length) == 0) {
101                         asprintf(tty_node, "%s/%s%d", TTY_DEV_BASE, TTY_NODE_BASE, i);
102
103                         free(tty_sysfs_node);
104                         return 0;
105                 } else {
106                         free(tty_sysfs_node);
107                 }
108         }
109
110         *tty_node = NULL;
111
112         return -1;
113 }
114
115 int gta04_transport_open(void *sdata)
116 {
117         struct gta04_transport_data *transport_data = NULL;
118         struct termios term;
119         char *dev_node = NULL;
120         int fd = -1;
121         int rc = -1;
122
123         if(sdata == NULL)
124                 return -1;
125
126         transport_data = (struct gta04_transport_data *) sdata;
127
128         // Open Modem node
129         if(transport_data->modem_fd <= 0) {
130                 rc = gta04_transport_find_node(&dev_node, "Modem");
131                 if(rc < 0) {
132                         LOGE("Unable to find Modem node, aborting!");
133                         goto failure;
134                 }
135
136                 fd = open(dev_node, O_RDWR | O_NOCTTY | O_NDELAY);
137                 if(fd < 0) {
138                         LOGE("Unable to open Modem node, aborting!");
139                         goto failure;
140                 }
141
142                 rc = tcgetattr(fd, &term);
143                 if(rc < 0) {
144                         LOGE("Unable to get Modem note attrs, aborting!");
145                         goto failure;
146                 }
147
148                 term.c_lflag &= ~(ECHO | ECHONL | ICANON | IEXTEN | ISIG);
149                 cfsetispeed(&term, B115200);
150                 cfsetospeed(&term, B115200);
151
152                 rc = tcsetattr(fd, TCSANOW, &term);
153                 if(rc < 0) {
154                         LOGE("Unable to set Modem note attrs, aborting!");
155                         goto failure;
156                 }
157
158                 LOGD("Opened Modem node");
159                 transport_data->modem_fd = fd;
160         }
161
162         // Open Application node
163         if(transport_data->application_fd <= 0) {
164                 rc = gta04_transport_find_node(&dev_node, "Application");
165                 if(rc < 0) {
166                         LOGE("Unable to find Application node, aborting!");
167                         goto failure;
168                 }
169
170                 fd = open(dev_node, O_RDWR | O_NOCTTY | O_NDELAY);
171                 if(fd < 0) {
172                         LOGE("Unable to open Application node, aborting!");
173                         goto failure;
174                 }
175
176                 rc = tcgetattr(fd, &term);
177                 if(rc < 0) {
178                         LOGE("Unable to get Application note attrs, aborting!");
179                         goto failure;
180                 }
181
182                 term.c_lflag &= ~(ECHO | ECHONL | ICANON | IEXTEN | ISIG);
183                 cfsetispeed(&term, B115200);
184                 cfsetospeed(&term, B115200);
185
186                 rc = tcsetattr(fd, TCSANOW, &term);
187                 if(rc < 0) {
188                         LOGE("Unable to set Application note attrs, aborting!");
189                         goto failure;
190                 }
191
192                 LOGD("Opened Application node");
193                 transport_data->application_fd = fd;
194         }
195
196         return 0;
197
198 failure:
199         if(dev_node != NULL)
200                 free(dev_node);
201
202         return -1;
203 }
204
205 int gta04_transport_close(void *sdata)
206 {
207         struct gta04_transport_data *transport_data = NULL;
208
209         if(sdata == NULL)
210                 return -1;
211
212         transport_data = (struct gta04_transport_data *) sdata;
213
214         if(transport_data->modem_fd > 0)
215                 close(transport_data->modem_fd);
216
217         if(transport_data->application_fd > 0)
218                 close(transport_data->application_fd);
219
220         return 0;
221 }
222
223 int gta04_transport_send(void *sdata, void *data, int length)
224 {
225         struct gta04_transport_data *transport_data = NULL;
226
227         // Written data count
228         int wc;
229         // Min count
230         int mc;
231         // Total written data count
232         int tc = 0;
233
234         if(sdata == NULL || data == NULL || length <= 0)
235                 return -1;
236
237         transport_data = (struct gta04_transport_data *) sdata;
238
239         if(transport_data->modem_fd < 0)
240                 return -1;
241
242         mc = length;
243         while(mc > 0) {
244                 // Outgoing AT data must be written to the Modem node apparently
245                 wc = write(transport_data->modem_fd, data + (length - mc), mc);
246                 if(wc < 0)
247                         return -1;
248
249                 tc += wc;
250                 mc -= wc;
251         }
252
253         return tc;
254 }
255
256 int gta04_transport_recv(void *sdata, void **data, int length)
257 {
258         struct gta04_transport_data *transport_data = NULL;
259         char *buffer;
260         int fd;
261
262         // Read data count
263         int rc;
264         // Min count
265         int mc;
266         // Total read data count
267         int tc = 0;
268
269         if(sdata == NULL)
270                 return -1;
271
272         transport_data = (struct gta04_transport_data *) sdata;
273
274         if(transport_data->modem_fd < 0)
275                 return -1;
276         if(transport_data->application_fd < 0)
277                 return -1;
278
279         if(transport_data->modem_ac > 0) {
280                 fd = transport_data->modem_fd;
281                 mc = transport_data->modem_ac;
282         } else if(transport_data->application_ac > 0) {
283                 fd = transport_data->application_fd;
284                 mc = transport_data->application_ac;
285         }
286
287         if(fd < 0)
288                 return -1;
289
290         if(length == 1 && mc == 1) {
291                 // Read an unknown number of bytes
292
293                 buffer = (char *) calloc(1, mc);
294
295                 rc = read(fd, (void *) buffer, RECV_BYTES_MAX);
296                 if(rc < 0) {
297                         free(buffer);
298                         return -1;
299                 }
300
301                 tc = rc;
302         } else {
303                 // Read the exact number of bytes
304
305                 buffer = (char *) calloc(1, mc);
306
307                 while(mc > 0) {
308                         rc = read(fd, (void *) (buffer + tc), mc - tc);
309                         if(rc < 0) {
310                                 free(buffer);
311                                 return -1;
312                         }
313
314                         tc += rc;
315                         mc -= rc;
316                 }
317
318                 if(tc > length)
319                         tc = length;
320         }
321
322         *data = (void *) buffer;
323
324         if(transport_data->modem_ac > 0)
325                 transport_data->modem_ac = 0;
326         else if(transport_data->application_ac > 0)
327                 transport_data->application_ac = 0;
328
329         return tc;
330 }
331
332 int gta04_transport_recv_poll(void *sdata)
333 {
334         struct gta04_transport_data *transport_data = NULL;
335         fd_set fds;
336
337         if(sdata == NULL)
338                 return -1;
339
340         transport_data = (struct gta04_transport_data *) sdata;
341
342         if(transport_data->modem_fd < 0)
343                 return -1;
344         if(transport_data->application_fd < 0)
345                 return -1;
346
347         FD_ZERO(&fds);
348         FD_SET(transport_data->modem_fd, &fds);
349         FD_SET(transport_data->application_fd, &fds);
350
351         select(FD_SETSIZE, &fds, NULL, NULL, NULL);
352
353         // Process one at a time
354         if(FD_ISSET(transport_data->modem_fd, &fds)) {
355                 transport_data->modem_ac = 1;
356         } else if(FD_ISSET(transport_data->application_fd, &fds)) {
357                 transport_data->application_ac = 1;
358         }
359
360         return 1;
361 }
362
363 int gta04_dummy(void *sdata)
364 {
365         return 0;
366 }
367
368 struct ril_device_power_handlers gta04_power_handlers = {
369         .sdata = NULL,
370         .sdata_create = gta04_dummy,
371         .sdata_destroy = gta04_dummy,
372         .power_on = gta04_dummy,
373         .power_off = gta04_dummy,
374         .suspend = gta04_dummy,
375         .resume = gta04_dummy,
376         .boot = gta04_power_boot,
377 };
378
379 struct ril_device_transport_handlers gta04_transport_handlers = {
380         .sdata = NULL,
381         .sdata_create = gta04_transport_sdata_create,
382         .sdata_destroy = gta04_transport_sdata_destroy,
383         .open = gta04_transport_open,
384         .close = gta04_transport_close,
385         .send = gta04_transport_send,
386         .recv = gta04_transport_recv,
387         .recv_poll = gta04_transport_recv_poll,
388 };
389
390 struct ril_device_handlers gta04_handlers = {
391         .power = &gta04_power_handlers,
392         .transport = &gta04_transport_handlers,
393 };
394
395 struct ril_device gta04_device = {
396         .name = "Goldelico GTA04",
397         .type = DEV_GSM,
398         .sdata = NULL,
399         .handlers = &gta04_handlers,
400 };
401
402 void ril_device_register(struct ril_device **ril_device_p)
403 {
404         *ril_device_p = &gta04_device;
405 }