GTA04: Added power handlers and fixed transport handlers
[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_count_nodes(void)
32 {
33         struct stat tty_node_stat;
34         char *tty_node = NULL;
35         int tty_nodes_count = 0;
36         int rc;
37         int i;
38
39         // Count how many nodes are available
40         for(i=0 ; i < TTY_NODE_MAX ; i++) {
41                 asprintf(&tty_node, "%s/%s%d", TTY_DEV_BASE, TTY_NODE_BASE, i);
42
43                 rc = stat(tty_node, &tty_node_stat);
44                 if(rc == 0)
45                         tty_nodes_count++;
46
47                 free(tty_node);
48         }
49
50         return tty_nodes_count;
51 }
52
53 int gta04_power_on(void *sdata)
54 {
55         char gpio_sysfs_value[] = "1\n";
56         int tty_nodes_count;
57         int fd;
58
59         tty_nodes_count = gta04_power_count_nodes();
60         if(tty_nodes_count < 2) {
61                 LOGD("Powering modem on");
62
63                 fd = open(GPIO_SYSFS, O_RDWR);
64                 if(fd < 0) {
65                         LOGE("Unable to open GPIO SYSFS node, modem will stay off");
66                         return -1;
67                 }
68
69                 write(fd, gpio_sysfs_value, strlen(gpio_sysfs_value));
70                 sleep(1);
71
72                 return 0;
73         }
74
75         LOGD("Modem is already on");
76         return 0;
77 }
78
79 int gta04_power_off(void *sdata)
80 {
81         char gpio_sysfs_value_0[] = "0\n";
82         char gpio_sysfs_value_1[] = "1\n";
83         int tty_nodes_count;
84         int fd;
85
86         tty_nodes_count = gta04_power_count_nodes();
87         if(tty_nodes_count > 0) {
88                 LOGD("Powering modem off");
89
90                 fd = open(GPIO_SYSFS, O_RDWR);
91                 if(fd < 0) {
92                         LOGE("Unable to open GPIO SYSFS node, modem will stay on");
93                         return -1;
94                 }
95
96                 write(fd, gpio_sysfs_value_0, strlen(gpio_sysfs_value_0));
97                 usleep(500);
98                 write(fd, gpio_sysfs_value_1, strlen(gpio_sysfs_value_1));
99                 usleep(500);
100                 write(fd, gpio_sysfs_value_0, strlen(gpio_sysfs_value_0));
101                 sleep(1);
102
103                 return 0;
104         }
105
106         LOGD("Modem is already off");
107         return 0;
108 }
109
110 int gta04_power_boot(void *sdata)
111 {
112         int tty_nodes_count;
113
114         tty_nodes_count = gta04_power_count_nodes();
115         if(tty_nodes_count < 2) {
116                 // We need at least Modem and Application
117                 LOGE("Not enough modem nodes available!");
118                 return -1;
119         }
120
121         return 0;
122 }
123
124 int gta04_transport_sdata_create(void **sdata)
125 {
126         struct gta04_transport_data *transport_data = NULL;
127
128         transport_data = malloc(sizeof(struct gta04_transport_data));
129         memset(transport_data, 0, sizeof(struct gta04_transport_data));
130
131         *sdata = (void *) transport_data;
132
133         return 0;
134 }
135
136 int gta04_transport_sdata_destroy(void *sdata)
137 {
138         if(sdata != NULL)
139                 free(sdata);
140
141         return 0;
142 }
143
144 int gta04_transport_find_node(char **tty_node, char *name)
145 {
146         char *tty_sysfs_node = NULL;
147         char *buf = NULL;
148         int name_length;
149         int fd = -1;
150         int i;
151
152         if(tty_node == NULL || name == NULL)
153                 return -1;
154
155         name_length = strlen(name);
156         buf = calloc(1, name_length);
157
158         for(i=0 ; i < TTY_NODE_MAX ; i++) {
159                 asprintf(&tty_sysfs_node, "%s/%s%d/%s",
160                         TTY_SYSFS_BASE, TTY_NODE_BASE, i, TTY_HSOTYPE);
161
162                 fd = open(tty_sysfs_node, O_RDONLY);
163                 if(fd < 0) {
164                         free(tty_sysfs_node);
165                         continue;
166                 }
167
168                 read(fd, buf, name_length);
169                 if(strncmp(name, buf, name_length) == 0) {
170                         asprintf(tty_node, "%s/%s%d", TTY_DEV_BASE, TTY_NODE_BASE, i);
171
172                         free(tty_sysfs_node);
173                         return 0;
174                 } else {
175                         free(tty_sysfs_node);
176                 }
177         }
178
179         *tty_node = NULL;
180
181         return -1;
182 }
183
184 int gta04_transport_open(void *sdata)
185 {
186         struct gta04_transport_data *transport_data = NULL;
187         struct termios term;
188         char *dev_node = NULL;
189         int fd = -1;
190         int rc = -1;
191
192         if(sdata == NULL)
193                 return -1;
194
195         transport_data = (struct gta04_transport_data *) sdata;
196
197         // Open Modem node
198         if(transport_data->modem_fd <= 0) {
199                 rc = gta04_transport_find_node(&dev_node, "Modem");
200                 if(rc < 0) {
201                         LOGE("Unable to find Modem node, aborting!");
202                         goto failure;
203                 }
204
205                 fd = open(dev_node, O_RDWR | O_NOCTTY | O_NDELAY);
206                 if(fd < 0) {
207                         LOGE("Unable to open Modem node, aborting!");
208                         goto failure;
209                 }
210
211                 rc = tcgetattr(fd, &term);
212                 if(rc < 0) {
213                         LOGE("Unable to get Modem note attrs, aborting!");
214                         goto failure;
215                 }
216
217                 term.c_lflag &= ~(ECHO | ECHONL | ICANON | IEXTEN | ISIG);
218                 cfsetispeed(&term, B115200);
219                 cfsetospeed(&term, B115200);
220
221                 rc = tcsetattr(fd, TCSANOW, &term);
222                 if(rc < 0) {
223                         LOGE("Unable to set Modem note attrs, aborting!");
224                         goto failure;
225                 }
226
227                 LOGD("Opened Modem node");
228                 transport_data->modem_fd = fd;
229         }
230
231         // Open Application node
232         if(transport_data->application_fd <= 0) {
233                 rc = gta04_transport_find_node(&dev_node, "Application");
234                 if(rc < 0) {
235                         LOGE("Unable to find Application node, aborting!");
236                         goto failure;
237                 }
238
239                 fd = open(dev_node, O_RDWR | O_NOCTTY | O_NDELAY);
240                 if(fd < 0) {
241                         LOGE("Unable to open Application node, aborting!");
242                         goto failure;
243                 }
244
245                 rc = tcgetattr(fd, &term);
246                 if(rc < 0) {
247                         LOGE("Unable to get Application note attrs, aborting!");
248                         goto failure;
249                 }
250
251                 term.c_lflag &= ~(ECHO | ECHONL | ICANON | IEXTEN | ISIG);
252                 cfsetispeed(&term, B115200);
253                 cfsetospeed(&term, B115200);
254
255                 rc = tcsetattr(fd, TCSANOW, &term);
256                 if(rc < 0) {
257                         LOGE("Unable to set Application note attrs, aborting!");
258                         goto failure;
259                 }
260
261                 LOGD("Opened Application node");
262                 transport_data->application_fd = fd;
263         }
264
265         return 0;
266
267 failure:
268         if(dev_node != NULL)
269                 free(dev_node);
270
271         return -1;
272 }
273
274 int gta04_transport_close(void *sdata)
275 {
276         struct gta04_transport_data *transport_data = NULL;
277
278         if(sdata == NULL)
279                 return -1;
280
281         transport_data = (struct gta04_transport_data *) sdata;
282
283         if(transport_data->modem_fd > 0)
284                 close(transport_data->modem_fd);
285
286         if(transport_data->application_fd > 0)
287                 close(transport_data->application_fd);
288
289         return 0;
290 }
291
292 int gta04_transport_send(void *sdata, void *data, int length)
293 {
294         struct gta04_transport_data *transport_data = NULL;
295
296         // Written data count
297         int wc;
298         // Min count
299         int mc;
300         // Total written data count
301         int tc = 0;
302
303         if(sdata == NULL || data == NULL || length <= 0)
304                 return -1;
305
306         transport_data = (struct gta04_transport_data *) sdata;
307
308         if(transport_data->modem_fd < 0)
309                 return -1;
310
311         mc = length;
312         while(mc > 0) {
313                 // Outgoing AT data must be written to the Modem node apparently
314                 wc = write(transport_data->modem_fd, data + (length - mc), mc);
315                 if(wc < 0)
316                         return -1;
317
318                 tc += wc;
319                 mc -= wc;
320         }
321
322         return tc;
323 }
324
325 int gta04_transport_recv(void *sdata, void **data, int length)
326 {
327         struct gta04_transport_data *transport_data = NULL;
328         char *buffer;
329         int fd;
330
331         // Read data count
332         int rc;
333         // Min count
334         int mc;
335         // Total read data count
336         int tc = 0;
337
338         if(sdata == NULL)
339                 return -1;
340
341         transport_data = (struct gta04_transport_data *) sdata;
342
343         if(transport_data->modem_fd < 0)
344                 return -1;
345         if(transport_data->application_fd < 0)
346                 return -1;
347
348         if(transport_data->modem_ac > 0) {
349                 fd = transport_data->modem_fd;
350                 mc = transport_data->modem_ac;
351         } else if(transport_data->application_ac > 0) {
352                 fd = transport_data->application_fd;
353                 mc = transport_data->application_ac;
354         }
355
356         if(fd < 0)
357                 return -1;
358
359         if(length == 1 && mc == 1) {
360                 // Read an unknown number of bytes
361
362                 buffer = (char *) calloc(1, RECV_BYTES_MAX);
363
364                 rc = read(fd, (void *) buffer, RECV_BYTES_MAX);
365                 if(rc < 0) {
366                         free(buffer);
367                         return -1;
368                 }
369
370                 tc = rc;
371         } else {
372                 // Read the exact number of bytes
373
374                 buffer = (char *) calloc(1, mc);
375
376                 while(mc > 0) {
377                         rc = read(fd, (void *) (buffer + tc), mc - tc);
378                         if(rc < 0) {
379                                 free(buffer);
380                                 return -1;
381                         }
382
383                         tc += rc;
384                         mc -= rc;
385                 }
386
387                 if(tc > length)
388                         tc = length;
389         }
390
391         *data = (void *) buffer;
392
393         if(transport_data->modem_ac > 0)
394                 transport_data->modem_ac = 0;
395         else if(transport_data->application_ac > 0)
396                 transport_data->application_ac = 0;
397
398         return tc;
399 }
400
401 int gta04_transport_recv_poll(void *sdata)
402 {
403         struct gta04_transport_data *transport_data = NULL;
404         fd_set fds;
405
406         if(sdata == NULL)
407                 return -1;
408
409         transport_data = (struct gta04_transport_data *) sdata;
410
411         if(transport_data->modem_fd < 0)
412                 return -1;
413         if(transport_data->application_fd < 0)
414                 return -1;
415
416         FD_ZERO(&fds);
417         FD_SET(transport_data->modem_fd, &fds);
418         FD_SET(transport_data->application_fd, &fds);
419
420         select(FD_SETSIZE, &fds, NULL, NULL, NULL);
421
422         // Process one at a time
423         if(FD_ISSET(transport_data->modem_fd, &fds)) {
424                 transport_data->modem_ac = 1;
425         } else if(FD_ISSET(transport_data->application_fd, &fds)) {
426                 transport_data->application_ac = 1;
427         }
428
429         return 1;
430 }
431
432 int gta04_dummy(void *sdata)
433 {
434         return 0;
435 }
436
437 struct ril_device_power_handlers gta04_power_handlers = {
438         .sdata = NULL,
439         .sdata_create = gta04_dummy,
440         .sdata_destroy = gta04_dummy,
441         .power_on = gta04_power_on,
442         .power_off = gta04_power_off,
443         .suspend = gta04_dummy,
444         .resume = gta04_dummy,
445         .boot = gta04_power_boot,
446 };
447
448 struct ril_device_transport_handlers gta04_transport_handlers = {
449         .sdata = NULL,
450         .sdata_create = gta04_transport_sdata_create,
451         .sdata_destroy = gta04_transport_sdata_destroy,
452         .open = gta04_transport_open,
453         .close = gta04_transport_close,
454         .send = gta04_transport_send,
455         .recv = gta04_transport_recv,
456         .recv_poll = gta04_transport_recv_poll,
457 };
458
459 struct ril_device_handlers gta04_handlers = {
460         .power = &gta04_power_handlers,
461         .transport = &gta04_transport_handlers,
462 };
463
464 struct ril_device gta04_device = {
465         .name = "Goldelico GTA04",
466         .tag = "GTA04",
467         .type = DEV_GSM,
468         .sdata = NULL,
469         .handlers = &gta04_handlers,
470 };
471
472 void ril_device_register(struct ril_device **ril_device_p)
473 {
474         *ril_device_p = &gta04_device;
475 }