Initial refactoring merge
[platform/core/telephony/tel-plugin-vmodem.git] / src / vdpram.c
1 /*\r
2  * tel-plugin-vmodem\r
3  *\r
4  * Copyright (c) 2013 Samsung Electronics Co. Ltd. All rights reserved.\r
5  *\r
6  * Licensed under the Apache License, Version 2.0 (the "License");\r
7  * you may not use this file except in compliance with the License.\r
8  * You may obtain a copy of the License at\r
9  *\r
10  * http://www.apache.org/licenses/LICENSE-2.0\r
11  *\r
12  * Unless required by applicable law or agreed to in writing, software\r
13  * distributed under the License is distributed on an "AS IS" BASIS,\r
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
15  * See the License for the specific language governing permissions and\r
16  * limitations under the License.\r
17  */\r
18 \r
19 #include <string.h>\r
20 #include <stdlib.h>\r
21 #include <stdio.h>\r
22 #include <termios.h>\r
23 #include <errno.h>\r
24 #include <sys/time.h>\r
25 #include <sys/mman.h>\r
26 #include <unistd.h>\r
27 #include <fcntl.h>\r
28 #include <sys/ioctl.h>\r
29 \r
30 #include <glib.h>
31
32 #include <log.h>\r
33 \r
34 #include "vdpram.h"\r
35 \r
36 #ifndef TIOCMODG\r
37 #  ifdef TIOCMGET\r
38 #    define TIOCMODG TIOCMGET\r
39 #  else\r
40 #    ifdef MCGETA\r
41 #      define TIOCMODG MCGETA\r
42 #    endif\r
43 #  endif\r
44 #endif\r
45 \r
46 #ifndef TIOCMODS\r
47 #  ifdef TIOCMSET\r
48 #    define TIOCMODS TIOCMSET\r
49 #  else\r
50 #    ifdef MCSETA\r
51 #      define TIOCMODS MCSETA\r
52 #    endif\r
53 #  endif\r
54 #endif\r
55 \r
56 #define VDPRAM_OPEN_PATH                "/dev/vdpram0"\r
57 \r
58 /* DPRAM ioctls for DPRAM tty devices */\r
59 #define IOC_MZ_MAGIC                    ('h')\r
60 #define HN_DPRAM_PHONE_ON               _IO (IOC_MZ_MAGIC, 0xd0)\r
61 #define HN_DPRAM_PHONE_OFF              _IO (IOC_MZ_MAGIC, 0xd1)\r
62 #define HN_DPRAM_PHONE_GETSTATUS        _IOR(IOC_MZ_MAGIC, 0xd2, guint)\r
63 \r
64 /* Retry parameters */
65 #define SLEEP_TIME_IN_SEC               0
66 #define SLEEP_TIME_IN_MSEC              50
67
68 #define MAX_RETRY_COUNT         10
69
70 typedef struct tty_old_setting TtyOldSetting;\r
71 \r
72 struct tty_old_setting {
73         gint fd;\r
74         struct termios termiosVal;\r
75         TtyOldSetting *next;\r
76         TtyOldSetting *prev;\r
77 };\r
78 \r
79 static TtyOldSetting *ttyold_head = NULL;\r
80 \r
81 /*
82  * Insert TTY old settings
83  */
84 static void __insert_tty_oldsetting(TtyOldSetting *me)\r
85 {\r
86         dbg("Enter");
87 \r
88         if (me == NULL)\r
89                 return;\r
90 \r
91         if (ttyold_head)\r
92                 ttyold_head->prev = me;
93 \r
94         me->next = ttyold_head;\r
95         me->prev = 0;\r
96         ttyold_head = me;\r
97 }\r
98 \r
99 /*
100  * Search TTY old settings
101  */
102 static TtyOldSetting *__search_tty_oldsetting(gint fd)\r
103 {\r
104         TtyOldSetting *tty = ttyold_head;\r
105 \r
106         dbg("Enter");
107 \r
108         while (tty) {\r
109                 if (tty->fd == fd) {\r
110                         dbg("tty for fd [%d] found!!!", fd);
111                         break;\r
112                 }\r
113                 tty = tty->next;\r
114         };\r
115 \r
116         return tty;\r
117 }\r
118 \r
119 /*
120  * Remove TTY old settings
121  */
122 static void __remove_tty_oldsetting(TtyOldSetting *me)\r
123 {\r
124         dbg("Enter");\r
125 \r
126         if (me == NULL)\r
127                 return;\r
128 \r
129         if (me->prev)\r
130                 me->prev->next = me->next;
131         else\r
132                 ttyold_head = me->next;
133 \r
134         if (me->next)\r
135                 me->next->prev = me->prev;
136 }\r
137 \r
138 /*
139  * Set hardware flow control
140  */
141 static void __tty_sethwf(gint fd, gint on)\r
142 {\r
143         struct termios tty;\r
144 \r
145         dbg("Enter");
146 \r
147         if (tcgetattr(fd, &tty))\r
148                 err("__tty_sethwf: tcgetattr:");\r
149 \r
150         if (on == 1)\r
151                 tty.c_cflag |= CRTSCTS;
152         else\r
153                 tty.c_cflag &= ~CRTSCTS;
154 \r
155         if (tcsetattr(fd, TCSANOW, &tty))\r
156                 err("__tty_sethwf: tcsetattr:");\r
157 }\r
158 \r
159 /*\r
160  * Set RTS line. Sometimes dropped. Linux specific?
161  */
162 static gint __tty_setrts(gint fd)\r
163 {\r
164         gint mcs;\r
165 \r
166         dbg("Enter");
167 \r
168         if (-1 ==  ioctl(fd, TIOCMODG, &mcs))\r
169                 err("icotl: TIOCMODG");\r
170 \r
171         mcs |= TIOCM_RTS;\r
172 \r
173         if (-1 == ioctl(fd, TIOCMODS, &mcs))\r
174                 err("icotl: TIOCMODS");\r
175 \r
176         return 0;\r
177 }\r
178 \r
179 /*\r
180  * Set baudrate, parity and number of bits
181  */\r
182 static gboolean __tty_setparms(gint fd,\r
183         gchar *baudr, gchar *par, gchar *bits, gchar *stop, gint hwf, gint swf)\r
184 {\r
185         gint spd = -1;\r
186         gint newbaud;\r
187         gint bit = bits[0];\r
188         gint stop_bit = stop[0];\r
189 \r
190         struct termios tty;\r
191         TtyOldSetting *old_setting = NULL;\r
192 \r
193         dbg("Enter");
194 \r
195         old_setting = g_try_new0(TtyOldSetting, 1);
196 \r
197         if (old_setting == NULL)\r
198                 return FALSE;\r
199 \r
200         old_setting->fd = fd;\r
201 \r
202         if (tcgetattr(fd, &tty) < 0) {\r
203                 g_free(old_setting);
204                 return FALSE;\r
205         }\r
206 \r
207         if (tcgetattr(fd, &old_setting->termiosVal) < 0) {\r
208                 g_free(old_setting);
209                 return FALSE;\r
210         }\r
211 \r
212         __insert_tty_oldsetting(old_setting);\r
213 \r
214         fflush(stdout);\r
215 \r
216         /* We generate mark and space parity ourself. */\r
217         if (bit == '7' && (par[0] == 'M' || par[0] == 'S'))\r
218                 bit = '8';\r
219 \r
220         /* Check if 'baudr' is really a number */\r
221         if ((newbaud = (atol(baudr) / 100)) == 0 && baudr[0] != '0')\r
222                 newbaud = -1;\r
223 \r
224         switch (newbaud) {
225         case 0:\r
226                 spd = 0;\r
227         break;
228 \r
229         case 3:\r
230                 spd = B300;\r
231         break;
232 \r
233         case 6:\r
234                 spd = B600;\r
235         break;
236 \r
237         case 12:\r
238                 spd = B1200;\r
239         break;
240 \r
241         case 24:\r
242                 spd = B2400;\r
243         break;
244 \r
245         case 48:\r
246                 spd = B4800;\r
247         break;
248 \r
249         case 96:\r
250                 spd = B9600;\r
251         break;
252 \r
253         case 192:\r
254                 spd = B19200;\r
255         break;
256 \r
257         case 384:\r
258                 spd = B38400;\r
259         break;
260 \r
261         case 576:\r
262                 spd = B57600;\r
263         break;
264 \r
265         case 1152:\r
266                 spd = B115200;\r
267         break;
268 \r
269         default:\r
270                 err("invaid baud rate");\r
271         break;
272         }\r
273 \r
274         if (spd != -1) {\r
275                 cfsetospeed(&tty, (speed_t) spd);
276                 cfsetispeed(&tty, (speed_t) spd);
277         }\r
278 \r
279         switch (bit) {
280         case '5':
281                 tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS5;
282         break;
283 \r
284         case '6':
285                 tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS6;
286         break;
287 \r
288         case '7':
289                 tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS7;
290         break;
291 \r
292         case '8':
293         default:
294                 tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8;
295         break;
296         }\r
297 \r
298         switch (stop_bit) {
299         case '1':
300                 tty.c_cflag &= ~CSTOPB;
301         break;
302 \r
303         case '2':
304         default:
305                 tty.c_cflag |= CSTOPB;
306         break;
307         }\r
308 \r
309         /* Set into raw, no echo mode */\r
310         tty.c_iflag = IGNBRK;\r
311         tty.c_lflag = 0;\r
312         tty.c_oflag = 0;\r
313         tty.c_cflag |= CLOCAL | CREAD;\r
314         tty.c_cc[VMIN] = 1;\r
315         tty.c_cc[VTIME] = 1;\r
316 \r
317         if (swf)\r
318                 tty.c_iflag |= IXON | IXOFF;
319         else\r
320                 tty.c_iflag &= ~(IXON | IXOFF | IXANY);
321 \r
322         tty.c_cflag &= ~(PARENB | PARODD);\r
323 \r
324         if (par[0] == 'E')\r
325                 tty.c_cflag |= PARENB;
326         else if (par[0] == 'O')\r
327                 tty.c_cflag |= (PARENB | PARODD);
328 \r
329         if (tcsetattr(fd, TCSANOW, &tty) < 0) {\r
330                 g_free(old_setting);
331                 return FALSE;
332         }\r
333 \r
334         __tty_setrts(fd);\r
335         __tty_sethwf(fd, hwf);\r
336 \r
337         return TRUE;\r
338 }\r
339 \r
340 /*
341  * Close TTY Device
342  */
343 static gboolean __tty_close(gint fd)\r
344 {\r
345         TtyOldSetting *old_setting = NULL;\r
346 \r
347         dbg("Enter");
348 \r
349         /* Get previous settings */
350         old_setting = __search_tty_oldsetting(fd);\r
351         if (old_setting == NULL) {
352                 dbg("No previous settings found!!!");
353                 return TRUE;\r
354         }
355 \r
356         if (tcsetattr(fd, TCSAFLUSH, &old_setting->termiosVal) < 0)     {\r
357                 err("Close failed");
358                 return FALSE;\r
359         }\r
360 \r
361         /* Remove the previous setting configured */
362         __remove_tty_oldsetting(old_setting);\r
363 \r
364         /* Free memory */
365         g_free(old_setting);
366 \r
367         /* Close fd */
368         close(fd);\r
369 \r
370         return TRUE;\r
371 }\r
372 \r
373 /*\r
374  * Wait on select
375  */
376 static void __sleep(gint sec, gint msec)
377 {
378         struct timeval tv;
379
380         tv.tv_sec = sec;
381         tv.tv_usec = msec;
382
383         select(0, NULL, NULL, NULL, &tv);
384 }
385
386 /*
387  * Close the VDPRAM device
388  */
389 gboolean vdpram_close(gint fd)\r
390 {\r
391         gint ret;\r
392 \r
393         dbg("Enter");
394 \r
395         /* Close VDPRAM Device */
396         ret = __tty_close(fd);\r
397 \r
398         return ret;\r
399 }\r
400 \r
401 /*\r
402  * Open the VDPRAM device
403  */
404 gint vdpram_open (void)\r
405 {\r
406         gint rv = -1;\r
407         gint fd = -1;\r
408         gint val = 0;\r
409         guint cmd =0;\r
410 \r
411         dbg("Enter");
412
413         /* Open DPRAM device */
414         fd = open(VDPRAM_OPEN_PATH, O_RDWR);\r
415         if (fd < 0) {\r
416                 err("Open VDPRAM file - [FAIL] Error: [%s]", strerror(errno));
417                 return rv;\r
418         } else {
419                 dbg("Open VDPRAM file - [SUCCESS] fd: [%d] path: [%s]",
420                         fd, VDPRAM_OPEN_PATH);
421         }\r
422 \r
423         /* Set device parameters */
424         if (__tty_setparms(fd, "115200", "N", "8", "1", 0, 0) != TRUE) {
425                 err("Set TTY device parameters - [FAIL]");
426 \r
427                 /* Close VDPRAM Device */
428                 (void)vdpram_close(fd);\r
429                 return rv;\r
430         }\r
431         else {
432                 dbg("Set TTY device parameters - [SUCCESS]");
433         }
434 \r
435         /* TODO: No need to check Status. Delete */
436         cmd = HN_DPRAM_PHONE_GETSTATUS;\r
437         if (ioctl(fd, cmd, &val) < 0) {
438                 err("Get Phone status - [FAIL] fd: [d] cmd: [%d] val: [%d]",
439                         fd, cmd, val);
440 \r
441                 /* Close Device */
442                 (void)vdpram_close(fd);\r
443
444                 return rv;\r
445         } else {
446                 dbg("Get Phone status - [SUCCESS]");
447         }\r
448 \r
449         return fd;\r
450 }\r
451 \r
452 /*\r
453  * Power ON the Phone
454  */
455 gboolean vdpram_poweron(gint fd)
456 {\r
457         if (ioctl(fd, HN_DPRAM_PHONE_ON, NULL) < 0) {\r
458                 err("Phone Power ON [FAIL] - fd: [%d] Error: [%s]", fd, strerror(errno));
459                 return FALSE;
460         }\r
461         else {\r
462                 dbg("Phone Power ON [SUCCESS] - fd: [%d]", fd);
463                 return TRUE;
464         }\r
465 }\r
466 \r
467 /*
468  * Power OFF the Phone
469  */\r
470 gboolean vdpram_poweroff(gint fd)
471 {\r
472         if (ioctl(fd, HN_DPRAM_PHONE_OFF, NULL) < 0) {\r
473                 err("Phone Power OFF [FAIL] - fd: [%d] Error: [%s]", fd, strerror(errno));
474                 return FALSE;
475         }\r
476         else {\r
477                 dbg("Phone Power OFF [SUCCESS] - fd: [%d]", fd);
478                 return TRUE;
479         }\r
480 }\r
481 \r
482 /*\r
483  * Read data from VDPRAM
484  */
485 gint vdpram_tty_read(gint fd, void *buf, size_t buf_len)\r
486 {\r
487         gint actual = 0;\r
488 \r
489         if ((actual = read(fd, buf, buf_len)) < 0) {\r
490                 err("Read [FAIL] - fd: [%d] Error: [%s]", fd, strerror(errno));
491         }\r
492
493         return actual;\r
494 }\r
495 \r
496 /*\r
497  * Write data to VDPRAM
498  */
499 gint vdpram_tty_write(gint fd, void *buf, size_t buf_len)\r
500 {\r
501         size_t actual = 0;\r
502         guint retry = 0;\r
503         gint ret;\r
504
505         while(actual < buf_len) {\r
506                 /* Write to Device */
507                 ret = write(fd, (guchar *)buf, buf_len - actual);\r
508                 if (ret < 0) {
509                         err("Write [FAIL] - fd: [%d] Error: [%s]",
510                                 fd, strerror(errno));
511 \r
512                         if ((errno == EAGAIN) || (errno == EBUSY)) {
513                                 /* Sleep for 50 msecs */
514                                 __sleep(SLEEP_TIME_IN_SEC, SLEEP_TIME_IN_MSEC);
515 \r
516                                 if (retry == MAX_RETRY_COUNT) {
517                                         err("Maximum retries completed!!!");
518                                         return 0;
519                                 }
520 \r
521                                 retry = retry + 1;
522                                 continue;
523                         }
524 \r
525                         if (actual != buf_len)
526                                 err("Write [FAIL] - fd: [%d]", fd);
527 \r
528                         err("Write [FAIL] - Error: [%s]", strerror(errno));
529                         return actual;\r
530                 }\r
531 \r
532                 actual  += ret;\r
533                 buf     += ret;\r
534                 dbg("Write Actual bytes: [%d] Written bytes: [%d]", actual, ret);
535         };\r
536 \r
537         return actual;\r
538 }\r