Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(338)

Side by Side Diff: plugins/mm-modem-samsung-gsm.c

Issue 6614026: modemmanager: Add support for Samsung Y3300 modem (Closed) Base URL: ssh://git@gitrw.chromium.org:9222/modemmanager.git@master
Patch Set: Created 9 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « plugins/mm-modem-samsung-gsm.h ('k') | plugins/mm-plugin-samsung.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details:
12 *
13 * Copyright (C) 2008 - 2009 Novell, Inc.
14 * Copyright (C) 2009 Red Hat, Inc.
15 * Copyright 2011 by Samsung Electronics, Inc.,
16 */
17
18 #include <stdlib.h>
19 #include <stdio.h>
20 #include <string.h>
21 #include <unistd.h>
22 #include <glib.h>
23 #include <errno.h>
24 #include <arpa/inet.h>
25 #include <dbus/dbus-glib.h>
26
27 #include "mm-modem-samsung-gsm.h"
28 #include "mm-modem-simple.h"
29 #include "mm-errors.h"
30 #include "mm-callback-info.h"
31 #include "mm-modem-gsm-card.h"
32
33 static void modem_init (MMModem *modem_class);
34 static void modem_gsm_network_init (MMModemGsmNetwork *gsm_network_class);
35 static void modem_simple_init (MMModemSimple *class);
36
37
38 G_DEFINE_TYPE_EXTENDED (MMModemSamsungGsm, mm_modem_samsung_gsm, MM_TYPE_GENERIC _GSM, 0,
39 G_IMPLEMENT_INTERFACE (MM_TYPE_MODEM, modem_init)
40 G_IMPLEMENT_INTERFACE (MM_TYPE_MODEM_SIMPLE, modem_simpl e_init)
41 G_IMPLEMENT_INTERFACE (MM_TYPE_MODEM_GSM_NETWORK, modem_ gsm_network_init))
42
43 #define MM_MODEM_SAMSUNG_GSM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), M M_TYPE_MODEM_SAMSUNG_GSM, MMModemSamsungGsmPrivate))
44
45 #define SAMSUNG_IPDPACT_DISCONNECTED 0
46 #define SAMSUNG_IPDPACT_CONNECTED 1
47 #define SAMSUNG_IPDPACT_CONNECTING 2
48 #define SAMSUNG_IPDPACT_CONNECTED_FAILED 3
49
50 typedef struct {
51 char * band;
52 MMCallbackInfo *connect_pending_data;
53 gboolean init_retried;
54
55 char *username;
56 char *password;
57
58 MMModemGsmAccessTech last_act;
59
60 } MMModemSamsungGsmPrivate;
61
62 #define IPDPADDR_TAG "%IPDPADDR: "
63
64
65 MMModem *
66 mm_modem_samsung_gsm_new (const char *device,
67 const char *driver,
68 const char *plugin)
69 {
70 g_return_val_if_fail (device != NULL, NULL);
71 g_return_val_if_fail (driver != NULL, NULL);
72 g_return_val_if_fail (plugin != NULL, NULL);
73
74 return MM_MODEM (g_object_new (MM_TYPE_MODEM_SAMSUNG_GSM,
75 MM_MODEM_MASTER_DEVICE, device,
76 MM_MODEM_DRIVER, driver,
77 MM_MODEM_PLUGIN, plugin,
78 MM_MODEM_IP_METHOD, MM_MODEM_IP_METHOD_DHCP,
79 NULL));
80 }
81
82 static void
83 connect_pending_done (MMModemSamsungGsm *self)
84 {
85 MMModemSamsungGsmPrivate *priv = MM_MODEM_SAMSUNG_GSM_GET_PRIVATE (self);
86 GError *error = NULL;
87
88 if (priv->connect_pending_data) {
89 if (priv->connect_pending_data->error) {
90 error = priv->connect_pending_data->error;
91 priv->connect_pending_data->error = NULL;
92 }
93
94 /* Complete the connect */
95 mm_generic_gsm_connect_complete (MM_GENERIC_GSM (self), error, priv->con nect_pending_data);
96 priv->connect_pending_data = NULL;
97 }
98 }
99
100 void
101 mm_modem_samsung_cleanup (MMModemSamsungGsm *self)
102 {
103 MMModemSamsungGsmPrivate *priv = MM_MODEM_SAMSUNG_GSM_GET_PRIVATE (self);
104
105 /* Clear the pending connection if necessary */
106 connect_pending_done (self);
107 g_free (priv->username);
108 g_free (priv->password);
109 memset (priv, 0, sizeof (MMModemSamsungGsmPrivate));
110 }
111
112 void
113 mm_modem_samsung_change_unsolicited_messages (MMModemSamsungGsm *self, gboolean enabled)
114 {
115 MMAtSerialPort *primary;
116
117 primary = mm_generic_gsm_get_at_port (MM_GENERIC_GSM (self), MM_PORT_TYPE_PR IMARY);
118 g_assert (primary);
119
120 mm_at_serial_port_queue_command (primary, enabled ? "%NWSTATE=1" : "%NWSTATE =0", 3, NULL, NULL);
121 }
122
123 typedef struct {
124 MMModemGsmBand mm;
125 char band[50];
126 } BandTable;
127
128 static BandTable bands[12] = {
129 /* Sort 3G first since it's preferred */
130 { MM_MODEM_GSM_BAND_U2100, "FDD_BAND_I" },
131 { MM_MODEM_GSM_BAND_U1900, "FDD_BAND_II" },
132 { MM_MODEM_GSM_BAND_U1800, "FDD_BAND_III" },
133 { MM_MODEM_GSM_BAND_U17IV, "FDD_BAND_IV" },
134 { MM_MODEM_GSM_BAND_U850, "FDD_BAND_V" },
135 { MM_MODEM_GSM_BAND_U800, "FDD_BAND_VI" },
136 { MM_MODEM_GSM_BAND_U900, "FDD_BAND_VIII" },
137 { MM_MODEM_GSM_BAND_G850, "G850" },
138 /* 2G second */
139 { MM_MODEM_GSM_BAND_DCS, "DCS" },
140 { MM_MODEM_GSM_BAND_EGSM, "EGSM" }, /* 0x100 = Extended GSM, 0x200 = Primar y GSM */
141 { MM_MODEM_GSM_BAND_PCS, "PCS" },
142 /* And ANY last since it's most inclusive */
143 { MM_MODEM_GSM_BAND_ANY, "ANY" },
144 };
145
146 static gboolean
147 band_mm_to_samsung (MMModemGsmBand band, MMModemGsmNetwork *modem)
148 {
149 int i;
150 MMModemSamsungGsmPrivate *priv = MM_MODEM_SAMSUNG_GSM_GET_PRIVATE (modem);
151
152 for (i = 0; i < sizeof (bands) / sizeof (BandTable); i++) {
153 if (bands[i].mm == band) {
154 priv->band = bands[i].band;
155 return TRUE;
156 }
157 }
158 return FALSE;
159 }
160
161 static gint samsung_get_cid (MMModemSamsungGsm *self)
162 {
163 gint cid;
164
165 cid = mm_generic_gsm_get_cid (MM_GENERIC_GSM (self));
166 if (cid < 0) {
167 g_warn_if_fail (cid >= 0);
168 cid = 0;
169 }
170
171 return cid;
172 }
173
174 static gboolean
175 parse_ipsys (MMModemSamsungGsm *self,
176 const char *reply,
177 int *mode,
178 int *domain,
179 MMModemGsmAllowedMode *out_mode)
180 {
181 if(reply == NULL || !g_str_has_prefix(reply, "%IPSYS:"))
182 return FALSE;
183
184 if (sscanf (reply + 7, "%d,%d", mode, domain) == 2) {
185 MMModemGsmAllowedMode new_mode = MM_MODEM_GSM_ALLOWED_MODE_ANY;
186
187 /* Network mode */
188 if (*mode == 2)
189 new_mode = MM_MODEM_GSM_ALLOWED_MODE_2G_PREFERRED;
190 else if (*mode == 3)
191 new_mode = MM_MODEM_GSM_ALLOWED_MODE_3G_PREFERRED;
192 else if (*mode == 0)
193 new_mode = MM_MODEM_GSM_ALLOWED_MODE_2G_ONLY;
194 else if (*mode == 1)
195 new_mode = MM_MODEM_GSM_ALLOWED_MODE_3G_ONLY;
196
197 if (out_mode)
198 *out_mode = new_mode;
199
200 return TRUE;
201 }
202
203 return FALSE;
204 }
205
206
207 static void
208 get_allowed_mode_done (MMAtSerialPort *port,
209 GString *response,
210 GError *error,
211 gpointer user_data)
212 {
213 MMCallbackInfo *info = (MMCallbackInfo *) user_data;
214 MMModemSamsungGsm *self = MM_MODEM_SAMSUNG_GSM (info->modem);
215 int mode, domain;
216 MMModemGsmAllowedMode mode_out = MM_MODEM_GSM_ALLOWED_MODE_ANY;
217
218 if (error)
219 info->error = g_error_copy (error);
220 else if (parse_ipsys (self, response->str, &mode, &domain, &mode_out))
221 mm_callback_info_set_result (info, GUINT_TO_POINTER (mode), NULL);
222
223 mm_callback_info_schedule (info);
224 }
225
226
227 static void
228 get_allowed_mode (MMGenericGsm *gsm,
229 MMModemUIntFn callback,
230 gpointer user_data)
231 {
232 MMCallbackInfo *info;
233 MMAtSerialPort *port;
234
235 info = mm_callback_info_uint_new (MM_MODEM (gsm), callback, user_data);
236
237 port = mm_generic_gsm_get_best_at_port (gsm, &info->error);
238 if (!port) {
239 mm_callback_info_schedule (info);
240 return;
241 }
242
243 mm_at_serial_port_queue_command (port, "AT%IPSYS?", 3, get_allowed_mode_done , info);
244 }
245
246 static void
247 set_allowed_mode_done (MMAtSerialPort *port,
248 GString *response,
249 GError *error,
250 gpointer user_data)
251 {
252 MMCallbackInfo *info = (MMCallbackInfo *) user_data;
253
254 if (error)
255 info->error = g_error_copy (error);
256
257 mm_callback_info_schedule (info);
258 }
259
260
261 static void
262 set_allowed_mode (MMGenericGsm *gsm,
263 MMModemGsmAllowedMode mode,
264 MMModemFn callback,
265 gpointer user_data)
266 {
267 MMCallbackInfo *info;
268 MMAtSerialPort *port;
269 int i;
270 char *command;
271
272 info = mm_callback_info_new (MM_MODEM (gsm), callback, user_data);
273
274 port = mm_generic_gsm_get_best_at_port (gsm, &info->error);
275 if (!port) {
276 mm_callback_info_schedule (info);
277 return;
278 }
279
280 switch (mode) {
281 case MM_MODEM_GSM_ALLOWED_MODE_2G_ONLY:
282 i = 0;
283 break;
284 case MM_MODEM_GSM_ALLOWED_MODE_3G_ONLY:
285 i = 1;
286 break;
287 case MM_MODEM_GSM_ALLOWED_MODE_2G_PREFERRED:
288 i = 2;
289 break;
290 case MM_MODEM_GSM_ALLOWED_MODE_3G_PREFERRED:
291 i = 3;
292 break;
293 case MM_MODEM_GSM_ALLOWED_MODE_ANY:
294 default:
295 i = 5;
296 break;
297 }
298
299 command = g_strdup_printf ("AT%%IPSYS=%d,3",i);
300
301 mm_at_serial_port_queue_command (port, command, 3, set_allowed_mode_done, in fo);
302 g_free (command);
303 }
304
305 static void
306 set_band_done (MMAtSerialPort *port,
307 GString *response,
308 GError *error,
309 gpointer user_data)
310 {
311 MMCallbackInfo *info = (MMCallbackInfo *) user_data;
312
313 if (error)
314 info->error = g_error_copy (error);
315
316 mm_callback_info_schedule (info);
317 }
318
319 static void
320 set_band (MMModemGsmNetwork *modem,
321 MMModemGsmBand band,
322 MMModemFn callback,
323 gpointer user_data)
324 {
325 MMCallbackInfo *info;
326 MMAtSerialPort *port;
327 char *command;
328 MMModemSamsungGsmPrivate *priv = MM_MODEM_SAMSUNG_GSM_GET_PRIVATE (modem);
329
330 info = mm_callback_info_new (MM_MODEM (modem), callback, user_data);
331
332 port = mm_generic_gsm_get_best_at_port (MM_GENERIC_GSM (modem), &info->error );
333 if (!port) {
334 mm_callback_info_schedule (info);
335 return;
336 }
337
338 if (!band_mm_to_samsung (band, modem)) {
339 info->error = g_error_new_literal (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERA L, "Invalid band.");
340 mm_callback_info_schedule (info);
341 } else {
342 mm_callback_info_set_data (info, "band", g_strdup(priv->band), NULL);
343 command = g_strdup_printf ("AT%%IPBM=\"%s\",1", priv->band);
344 mm_at_serial_port_queue_command (port, command, 3, set_band_done, info);
345 g_free (command);
346 priv->band = NULL;
347 }
348 }
349
350 static gboolean parse_ipbm(MMModemSamsungGsm *self,
351 const char *reply,
352 MMModemGsmBand *band)
353 {
354 int enable[12];
355
356 g_assert(band != NULL);
357
358 if (reply == NULL)
359 return FALSE;
360
361 if (sscanf (reply, "\"ANY\": %d\r\n\"EGSM\": %d\r\n\"DCS\": %d\r\n\"PCS\": % d\r\n\"G850\": %d\r\n\"FDD_BAND_I\": %d\r\n\"FDD_BAND_II\": %d\r\n\"FDD_BAND_III \": %d\r\n\"FDD_BAND_IV\": %d\r\n\"FDD_BAND_V\": %d\r\n\"FDD_BAND_VI\": %d\r\n\" FDD_BAND_VIII\": %d", &enable[0], &enable[1], &enable[2], &enable[3], &enable[4] , &enable[5], &enable[6], &enable[7], &enable[8], &enable[9], &enable[10], &enab le[11])== 12) {
362
363 if(enable[5] == 1) {
364 *band = MM_MODEM_GSM_BAND_U2100;
365 return TRUE;}
366 else if(enable[6] == 1) {
367 *band = MM_MODEM_GSM_BAND_U1900;
368 return TRUE;}
369 else if(enable[7] == 1) {
370 *band = MM_MODEM_GSM_BAND_U1800;
371 return TRUE;}
372 else if(enable[8] == 1) {
373 *band = MM_MODEM_GSM_BAND_U17IV;
374 return TRUE;}
375 else if(enable[9] == 1) {
376 *band = MM_MODEM_GSM_BAND_U850;
377 return TRUE;}
378 else if(enable[10] == 1) {
379 *band = MM_MODEM_GSM_BAND_U800;
380 return TRUE;}
381 else if(enable[11] == 1) {
382 *band = MM_MODEM_GSM_BAND_U900;
383 return TRUE;}
384 else if(enable[1] == 1) {
385 *band = MM_MODEM_GSM_BAND_EGSM;
386 return TRUE;}
387 else if(enable[2] == 1) {
388 *band = MM_MODEM_GSM_BAND_DCS;
389 return TRUE;}
390 else if(enable[3] == 1) {
391 *band = MM_MODEM_GSM_BAND_PCS;
392 return TRUE;}
393 else if(enable[4] == 1) {
394 *band = MM_MODEM_GSM_BAND_G850;
395 return TRUE;}
396 else{
397 *band = MM_MODEM_GSM_BAND_ANY;}
398
399 return TRUE;
400 }
401
402 return FALSE;
403 }
404
405 static void
406 get_band_done (MMAtSerialPort *port,
407 GString *response,
408 GError *error,
409 gpointer user_data)
410 {
411 MMCallbackInfo *info = (MMCallbackInfo *) user_data;
412 MMModemSamsungGsm *self = MM_MODEM_SAMSUNG_GSM (info->modem);
413 MMModemGsmBand mm_band = MM_MODEM_GSM_BAND_ANY;
414
415 if (error)
416 info->error = g_error_copy (error);
417 else if (parse_ipbm (self, response->str, &mm_band)) {
418
419 mm_callback_info_set_result (info, GUINT_TO_POINTER (mm_band), NULL);
420 }
421
422 mm_callback_info_schedule (info);
423 }
424
425 static void
426 get_band (MMModemGsmNetwork *modem,
427 MMModemUIntFn callback,
428 gpointer user_data)
429 {
430 MMAtSerialPort *port;
431 MMCallbackInfo *info;
432
433 info = mm_callback_info_uint_new (MM_MODEM (modem), callback, user_data);
434
435 /* Otherwise ask the modem */
436 port = mm_generic_gsm_get_best_at_port (MM_GENERIC_GSM (modem), &info->error );
437 if (!port) {
438 mm_callback_info_schedule (info);
439 return;
440 }
441
442 mm_at_serial_port_queue_command (port, "AT%IPBM?", 3, get_band_done, info);
443 }
444
445 static void
446 get_nwstate_done (MMAtSerialPort *port,
447 GString *response,
448 GError *error,
449 gpointer user_data)
450 {
451 MMCallbackInfo *info = user_data;
452
453 info->error = mm_modem_check_removed (info->modem, error);
454 if (!info->error) {
455 MMModemSamsungGsm *self = MM_MODEM_SAMSUNG_GSM (info->modem);
456 MMModemSamsungGsmPrivate *priv = MM_MODEM_SAMSUNG_GSM_GET_PRIVATE (self) ;
457
458 /* The unsolicited message handler will already have run and
459 * removed the NWSTATE response, so we have to work around that.
460 */
461 mm_callback_info_set_result (info, GUINT_TO_POINTER (priv->last_act), NU LL);
462 priv->last_act = MM_MODEM_GSM_ACCESS_TECH_UNKNOWN;
463 }
464
465 mm_callback_info_schedule (info);
466 }
467
468 static void
469 get_access_technology (MMGenericGsm *gsm,
470 MMModemUIntFn callback,
471 gpointer user_data)
472 {
473 MMModemSamsungGsm *self = MM_MODEM_SAMSUNG_GSM (gsm);
474 MMAtSerialPort *port;
475 MMCallbackInfo *info;
476
477 info = mm_callback_info_uint_new (MM_MODEM (self), callback, user_data);
478
479 port = mm_generic_gsm_get_best_at_port (MM_GENERIC_GSM (self), &info->error) ;
480 if (!port) {
481 mm_callback_info_schedule (info);
482 return;
483 }
484
485 mm_at_serial_port_queue_command (port, "%NWSTATE=1", 3, get_nwstate_done, in fo);
486 }
487
488 typedef struct {
489 MMModem *modem;
490 MMModemFn callback;
491 gpointer user_data;
492 } DisableInfo;
493
494 static void
495 disable_unsolicited_done (MMAtSerialPort *port,
496 GString *response,
497 GError *error,
498 gpointer user_data)
499
500 {
501 MMModem *parent_modem_iface;
502 DisableInfo *info = user_data;
503
504 parent_modem_iface = g_type_interface_peek_parent (MM_MODEM_GET_INTERFACE (i nfo->modem));
505 parent_modem_iface->disable (info->modem, info->callback, info->user_data);
506 g_free (info);
507 }
508
509 static void
510 disable (MMModem *modem,
511 MMModemFn callback,
512 gpointer user_data)
513 {
514 MMModemSamsungGsmPrivate *priv = MM_MODEM_SAMSUNG_GSM_GET_PRIVATE (modem);
515 MMAtSerialPort *primary;
516 DisableInfo *info;
517
518 priv->init_retried = FALSE;
519
520 info = g_malloc0 (sizeof (DisableInfo));
521 info->callback = callback;
522 info->user_data = user_data;
523 info->modem = modem;
524
525 primary = mm_generic_gsm_get_at_port (MM_GENERIC_GSM (modem), MM_PORT_TYPE_P RIMARY);
526 g_assert (primary);
527
528 /* Turn off unsolicited responses */
529 mm_modem_samsung_cleanup (MM_MODEM_SAMSUNG_GSM (modem));
530 mm_modem_samsung_change_unsolicited_messages (MM_MODEM_SAMSUNG_GSM (modem), FALSE);
531
532 /* Random command to ensure unsolicited message disable completes */
533 mm_at_serial_port_queue_command (primary, "AT+CFUN=0", 5, disable_unsolicite d_done, info);
534 }
535
536 static void
537 init_modem_done (MMAtSerialPort *port,
538 GString *response,
539 GError *error,
540 gpointer user_data)
541 {
542 MMCallbackInfo *info = (MMCallbackInfo *) user_data;
543
544 mm_at_serial_port_queue_command (port, "ATE0;+CFUN=1", 5, NULL, NULL);
545
546 mm_modem_samsung_change_unsolicited_messages (MM_MODEM_SAMSUNG_GSM (info->mo dem), TRUE);
547
548 mm_generic_gsm_enable_complete (MM_GENERIC_GSM (info->modem), error, info);
549 }
550
551 static void enable_flash_done (MMSerialPort *port,
552 GError *error,
553 gpointer user_data);
554
555 static void
556 pre_init_done (MMAtSerialPort *port,
557 GString *response,
558 GError *error,
559 gpointer user_data)
560 {
561 MMCallbackInfo *info = (MMCallbackInfo *) user_data;
562 MMModemSamsungGsm *self = MM_MODEM_SAMSUNG_GSM (info->modem);
563 MMModemSamsungGsmPrivate *priv = MM_MODEM_SAMSUNG_GSM_GET_PRIVATE (self);
564
565 if (error) {
566 /* Retry the init string one more time; the modem sometimes throws it aw ay */
567 if ( !priv->init_retried
568 && g_error_matches (error, MM_SERIAL_ERROR, MM_SERIAL_ERROR_RESPONSE _TIMEOUT)) {
569 priv->init_retried = TRUE;
570 enable_flash_done (MM_SERIAL_PORT (port), NULL, user_data);
571 } else
572 mm_generic_gsm_enable_complete (MM_GENERIC_GSM (self), error, info);
573 } else {
574 /* Finish the initialization */
575 mm_at_serial_port_queue_command (port, "Z E0 V1 X4 &C1 +CMEE=1;+CFUN=1;" , 10, init_modem_done, info);
576 }
577 }
578
579 static void
580 enable_flash_done (MMSerialPort *port, GError *error, gpointer user_data)
581 {
582 MMCallbackInfo *info = (MMCallbackInfo *) user_data;
583
584 if (error)
585 mm_generic_gsm_enable_complete (MM_GENERIC_GSM (info->modem), error, inf o);
586 else
587 mm_at_serial_port_queue_command (MM_AT_SERIAL_PORT (port), "E0 V1", 3, p re_init_done, user_data);
588 }
589
590 static void
591 do_enable (MMGenericGsm *modem, MMModemFn callback, gpointer user_data)
592 {
593 MMModemSamsungGsmPrivate *priv = MM_MODEM_SAMSUNG_GSM_GET_PRIVATE (modem);
594 MMCallbackInfo *info;
595 MMAtSerialPort *primary;
596
597 priv->init_retried = FALSE;
598
599 primary = mm_generic_gsm_get_at_port (modem, MM_PORT_TYPE_PRIMARY);
600 g_assert (primary);
601
602 info = mm_callback_info_new (MM_MODEM (modem), callback, user_data);
603 mm_serial_port_flash (MM_SERIAL_PORT (primary), 100, FALSE, enable_flash_don e, info);
604 }
605
606 static void
607 Samsung_call_control (MMModemSamsungGsm *self,
608 gboolean activate,
609 MMAtSerialResponseFn callback,
610 gpointer user_data)
611 {
612 char *command;
613 MMAtSerialPort *primary;
614
615 primary = mm_generic_gsm_get_at_port (MM_GENERIC_GSM (self), MM_PORT_TYPE_PR IMARY);
616 g_assert (primary);
617
618 command = g_strdup_printf ("%%IPDPACT=%d,%d", samsung_get_cid(self), activat e ? 1 : 0);
619 mm_at_serial_port_queue_command (primary, command, 3, callback, user_data);
620 g_free (command);
621 }
622
623 static void
624 Samsung_enabled (MMAtSerialPort *port,
625 GString *response,
626 GError *error,
627 gpointer user_data)
628 {
629 MMCallbackInfo *info = (MMCallbackInfo *) user_data;
630
631 if (error) {
632 mm_generic_gsm_connect_complete (MM_GENERIC_GSM (info->modem), error, in fo);
633 } else {
634 MMModemSamsungGsm *self = MM_MODEM_SAMSUNG_GSM (info->modem);
635 MMModemSamsungGsmPrivate *priv = MM_MODEM_SAMSUNG_GSM_GET_PRIVATE (self) ;
636
637 priv->connect_pending_data = info;
638 }
639 }
640
641 static void
642 auth_done (MMAtSerialPort *port,
643 GString *response,
644 GError *error,
645 gpointer user_data)
646 {
647 MMCallbackInfo *info = (MMCallbackInfo *) user_data;
648
649 if (error)
650 mm_generic_gsm_connect_complete (MM_GENERIC_GSM (info->modem), error, in fo);
651 else {
652 /* Activate the PDP context and start the data session */
653 Samsung_call_control (MM_MODEM_SAMSUNG_GSM (info->modem), TRUE, Samsung_enab led, info);
654 }
655 }
656
657 static void
658 old_context_clear_done (MMAtSerialPort *port,
659 GString *response,
660 GError *error,
661 gpointer user_data)
662 {
663 MMCallbackInfo *info = (MMCallbackInfo *) user_data;
664 gint cid;
665 char *command;
666 MMAtSerialPort *primary;
667
668 MMModemSamsungGsm *self = MM_MODEM_SAMSUNG_GSM (info->modem);
669 MMModemSamsungGsmPrivate *priv = MM_MODEM_SAMSUNG_GSM_GET_PRIVATE (self);
670
671 cid = samsung_get_cid (self);
672
673 primary = mm_generic_gsm_get_at_port (MM_GENERIC_GSM (self), MM_PORT_TYPE_PR IMARY);
674 g_assert (primary);
675
676 /* Both user and password are required; otherwise firmware returns an error */
677 if (!priv->username || !priv->password)
678 command = g_strdup_printf ("%%IPDPCFG=%d,0,0,\"\",\"\"", cid);
679 else {
680 command = g_strdup_printf ("%%IPDPCFG=%d,0,1,\"%s\",\"%s\"",
681 cid,
682 priv->password ? priv->password : "",
683 priv->username ? priv->username : "");
684
685 }
686
687 mm_at_serial_port_queue_command (primary, command, 3, auth_done, info);
688 g_free (command);
689 }
690
691 void
692 mm_modem_samsung_do_connect (MMModemSamsungGsm *self,
693 const char *number,
694 MMModemFn callback,
695 gpointer user_data)
696 {
697 MMModem *modem = MM_MODEM (self);
698 MMCallbackInfo *info;
699
700 mm_modem_set_state (modem, MM_MODEM_STATE_CONNECTING, MM_MODEM_STATE_REASON_ NONE);
701
702 info = mm_callback_info_new (modem, callback, user_data);
703
704
705 /* Ensure the PDP context is deactivated */
706 Samsung_call_control (MM_MODEM_SAMSUNG_GSM (info->modem), FALSE, old_context _clear_done, info);
707
708 }
709
710 static void
711 do_connect (MMModem *modem,
712 const char *number,
713 MMModemFn callback,
714 gpointer user_data)
715 {
716
717 mm_modem_samsung_do_connect (MM_MODEM_SAMSUNG_GSM (modem), number, callback, user_data);
718
719 }
720
721 static void
722 do_disconnect (MMGenericGsm *gsm,
723 gint cid,
724 MMModemFn callback,
725 gpointer user_data)
726 {
727 MMCallbackInfo *info;
728 MMAtSerialPort *primary;
729 char *command;
730
731 info = mm_callback_info_new (MM_MODEM (gsm), callback, user_data);
732
733 primary = mm_generic_gsm_get_at_port (gsm, MM_PORT_TYPE_PRIMARY);
734 g_assert (primary);
735
736 command = g_strdup_printf ("AT%%IPDPACT=%d,0", cid);
737
738 mm_at_serial_port_queue_command (primary, command, 3, NULL, NULL);
739 g_free (command);
740
741 MM_GENERIC_GSM_CLASS (mm_modem_samsung_gsm_parent_class)->do_disconnect (gsm , cid, callback, user_data);
742
743 }
744
745 static void
746 Samsung_disconnect_done (MMModem *modem,
747 GError *error,
748 gpointer user_data)
749 {
750 g_message ("Modem signaled disconnection from the network");
751 }
752
753 static void
754 connection_enabled (MMAtSerialPort *port,
755 GMatchInfo *match_info,
756 gpointer user_data)
757 {
758 MMModemSamsungGsm *self = MM_MODEM_SAMSUNG_GSM (user_data);
759 MMModemSamsungGsmPrivate *priv = MM_MODEM_SAMSUNG_GSM_GET_PRIVATE (self);
760 MMCallbackInfo *info = priv->connect_pending_data;
761 char *str;
762 int status, cid, tmp;
763
764 cid = mm_generic_gsm_get_cid (MM_GENERIC_GSM (self));
765 if (cid < 0)
766 return;
767
768 str = g_match_info_fetch (match_info, 1);
769 g_return_if_fail (str != NULL);
770 tmp = atoi (str);
771 g_free (str);
772
773 /* Make sure the unsolicited message's CID matches the current CID */
774 if (tmp != cid)
775 return;
776
777 str = g_match_info_fetch (match_info, 2);
778 g_return_if_fail (str != NULL);
779 status = atoi (str);
780 g_free (str);
781
782 switch (status) {
783 case 0:
784 /* Disconnected */
785 if (mm_modem_get_state (MM_MODEM (self)) >= MM_MODEM_STATE_CONNECTED)
786 mm_modem_disconnect (MM_MODEM (self), Samsung_disconnect_done, NULL) ;
787 break;
788 case 1:
789 /* Connected */
790 connect_pending_done (self);
791 break;
792 case 2:
793 /* Connecting */
794 break;
795 case 3:
796 /* Call setup failure? */
797 if (info) {
798 info->error = g_error_new_literal (MM_MODEM_ERROR,
799 MM_MODEM_ERROR_GENERAL,
800 "Call setup failed");
801 }
802 connect_pending_done (self);
803 break;
804 default:
805 g_warning ("Unknown Samsung connect status %d", status);
806 break;
807 }
808 }
809
810 static void
811 handle_mode_change (MMAtSerialPort *port,
812 GMatchInfo *match_info,
813 gpointer user_data)
814 {
815 MMModemSamsungGsm *self = MM_MODEM_SAMSUNG_GSM (user_data);
816 MMModemGsmAccessTech act = MM_MODEM_GSM_ACCESS_TECH_UNKNOWN;
817 char *str;
818 int rssi = -1;
819
820 str = g_match_info_fetch (match_info, 1);
821 if (str) {
822 rssi = atoi (str);
823 rssi = CLAMP (rssi, -1, 5);
824 g_free (str);
825 }
826
827 str = g_match_info_fetch (match_info, 3);
828
829 /* Better technologies are listed first since modems sometimes say
830 * stuff like "GPRS/EDGE" and that should be handled as EDGE.
831 */
832 g_debug ("Access Technology: %s", str);
833 if (strcmp (str, "3G-HSDPA-HSUPA")==0)
834 act = MM_MODEM_GSM_ACCESS_TECH_HSPA;
835 else if (strcmp (str, "3G-HSUPA")==0)
836 act = MM_MODEM_GSM_ACCESS_TECH_HSUPA;
837 else if (strcmp (str, "3G-HSDPA")==0)
838 act = MM_MODEM_GSM_ACCESS_TECH_HSDPA;
839 else if (strcmp (str, "3G")==0)
840 act = MM_MODEM_GSM_ACCESS_TECH_UMTS;
841 else if (strcmp (str, "3g")==0)
842 act = MM_MODEM_GSM_ACCESS_TECH_UMTS;
843 else if (strcmp (str, "2G-EDGE")==0)
844 act = MM_MODEM_GSM_ACCESS_TECH_EDGE;
845 else if (strcmp (str, "2G-GPRS")==0)
846 act = MM_MODEM_GSM_ACCESS_TECH_GPRS;
847 else if (strcmp (str, "2g")==0)
848 act = MM_MODEM_GSM_ACCESS_TECH_GSM;
849 else
850 act = MM_MODEM_GSM_ACCESS_TECH_UNKNOWN;
851 g_free (str);
852
853 g_debug ("Access Technology: %d", act);
854 MM_MODEM_SAMSUNG_GSM_GET_PRIVATE (self)->last_act = act;
855 mm_generic_gsm_update_access_technology (MM_GENERIC_GSM (self), act);
856 }
857
858 static void
859 free_dns_array (gpointer data)
860 {
861 g_array_free ((GArray *) data, TRUE);
862 }
863
864 static void
865 ip4_config_invoke (MMCallbackInfo *info)
866 {
867 MMModemIp4Fn callback = (MMModemIp4Fn) info->callback;
868
869 callback (info->modem,
870 GPOINTER_TO_UINT (mm_callback_info_get_data (info, "ip4-address")) ,
871 (GArray *) mm_callback_info_get_data (info, "ip4-dns"),
872 info->error, info->user_data);
873 }
874
875 static void
876 get_ip4_config_done (MMAtSerialPort *port,
877 GString *response,
878 GError *error,
879 gpointer user_data)
880 {
881 MMCallbackInfo *info = (MMCallbackInfo *) user_data;
882 char **items, **iter;
883 GArray *dns_array;
884 int i;
885 guint32 tmp;
886 gint cid;
887
888 if (error) {
889 info->error = g_error_copy (error);
890 goto out;
891 } else if (!g_str_has_prefix (response->str, IPDPADDR_TAG)) {
892 info->error = g_error_new_literal (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERA L,
893 "Retrieving failed: invalid response. ");
894 goto out;
895 }
896
897 cid = samsung_get_cid (MM_MODEM_SAMSUNG_GSM (info->modem));
898 dns_array = g_array_sized_new (FALSE, TRUE, sizeof (guint32), 2);
899 items = g_strsplit (response->str + strlen (IPDPADDR_TAG), ", ", 0);
900
901 /* Appending data from at%IPDPADDR command
902 * Skipping when i = 2. Gateway address is not what we want
903 */
904 for (iter = items, i = 0; *iter; iter++, i++) {
905 if (i == 0) { /* CID */
906 long int num;
907
908 errno = 0;
909 num = strtol (*iter, NULL, 10);
910 if (errno != 0 || num < 0 || (gint) num != cid) {
911 info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERA L,
912 "Unknown CID in OWANDATA response ("
913 "got %d, expected %d)", (guint) num, cid);
914 break;
915 }
916 } else if (i == 1) { /* IP address */
917 if (inet_pton (AF_INET, *iter, &tmp) > 0)
918 mm_callback_info_set_data (info, "ip4-address", GUINT_TO_POINTER (tmp), NULL);
919 } else if (i == 3) { /* DNS 1 */
920 if (inet_pton (AF_INET, *iter, &tmp) > 0)
921 g_array_append_val (dns_array, tmp);
922 } else if (i == 4) { /* DNS 2 */
923 if (inet_pton (AF_INET, *iter, &tmp) > 0)
924 g_array_append_val (dns_array, tmp);
925 }
926 }
927
928 g_strfreev (items);
929 mm_callback_info_set_data (info, "ip4-dns", dns_array, free_dns_array);
930
931 out:
932 mm_callback_info_schedule (info);
933 }
934
935
936 static void
937 get_ip4_config (MMModem *modem,
938 MMModemIp4Fn callback,
939 gpointer user_data)
940 {
941 MMCallbackInfo *info;
942 char *command;
943 MMAtSerialPort *primary;
944
945 info = mm_callback_info_new_full (modem, ip4_config_invoke, G_CALLBACK (call back), user_data);
946
947 command = g_strdup_printf ("AT%%IPDPADDR=%d", samsung_get_cid (MM_MODEM_SAMS UNG_GSM (modem)));
948
949 primary = mm_generic_gsm_get_at_port (MM_GENERIC_GSM (modem), MM_PORT_TYPE_P RIMARY);
950 g_assert (primary);
951
952 mm_at_serial_port_queue_command (primary, command, 3, get_ip4_config_done, i nfo);
953 g_free (command);
954 }
955
956 static const char *
957 get_string_property (GHashTable *properties, const char *name)
958 {
959 GValue *value;
960
961 value = (GValue *) g_hash_table_lookup (properties, name);
962 if (value && G_VALUE_HOLDS_STRING (value))
963 return g_value_get_string (value);
964 return NULL;
965 }
966
967 static void
968 simple_connect (MMModemSimple *simple,
969 GHashTable *properties,
970 MMModemFn callback,
971 gpointer user_data)
972 {
973 MMModemSamsungGsmPrivate *priv = MM_MODEM_SAMSUNG_GSM_GET_PRIVATE (simple);
974 MMCallbackInfo *info = (MMCallbackInfo *) user_data;
975 MMModemSimple *parent_iface;
976
977 g_free (priv->username);
978 priv->username = g_strdup (get_string_property (properties, "username"));
979 g_free (priv->password);
980 priv->password = g_strdup (get_string_property (properties, "password"));
981
982 parent_iface = g_type_interface_peek_parent (MM_MODEM_SIMPLE_GET_INTERFACE ( simple));
983 parent_iface->connect (MM_MODEM_SIMPLE (simple), properties, callback, info) ;
984
985 }
986
987 static gboolean
988 grab_port (MMModem *modem,
989 const char *subsys,
990 const char *name,
991 MMPortType suggested_type,
992 gpointer user_data,
993 GError **error)
994 {
995 MMGenericGsm *gsm = MM_GENERIC_GSM (modem);
996 MMPortType ptype = MM_PORT_TYPE_IGNORED;
997 MMPort *port = NULL;
998
999 if (suggested_type == MM_PORT_TYPE_UNKNOWN) {
1000 if(g_str_has_prefix(name, "usb"))
1001 ptype = MM_PORT_TYPE_ECM;
1002 else if (!mm_generic_gsm_get_at_port (gsm, MM_PORT_TYPE_PRIMARY))
1003 ptype = MM_PORT_TYPE_PRIMARY;
1004 else if (!mm_generic_gsm_get_at_port (gsm, MM_PORT_TYPE_SECONDARY))
1005 ptype = MM_PORT_TYPE_SECONDARY;
1006 } else
1007 ptype = suggested_type;
1008
1009 port = mm_generic_gsm_grab_port (gsm, subsys, name, ptype, error);
1010 if (port && MM_IS_AT_SERIAL_PORT (port)) {
1011 GRegex *regex;
1012
1013 g_object_set (port, MM_PORT_CARRIER_DETECT, FALSE, NULL);
1014
1015
1016 /* %NWSTATE: <rssi>,<mccmnc>,<tech>,<connected>,<regulation> */
1017 regex = g_regex_new ("\\r\\n\\%NWSTATE: (\\d),(\\d+),\\s*([^,\\s]*)\\s*, (.+)\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
1018 mm_at_serial_port_add_unsolicited_msg_handler (MM_AT_SERIAL_PORT (port), regex, handle_mode_change, modem, NULL);
1019 g_regex_unref (regex);
1020
1021 /* %IPDPACT: <cid>,<status>,0 */
1022 regex = g_regex_new ("\\r\\n%IPDPACT:\\s*(\\d+),\\s*(\\d+),\\s*(\\d+)\\r \\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
1023 mm_at_serial_port_add_unsolicited_msg_handler (MM_AT_SERIAL_PORT (port), regex, connection_enabled, modem, NULL);
1024 g_regex_unref (regex);
1025 }
1026
1027 return !!port;
1028 }
1029
1030 static void
1031 modem_init (MMModem *modem_class)
1032 {
1033 modem_class->disable = disable;
1034 modem_class->connect = do_connect;
1035 modem_class->get_ip4_config = get_ip4_config;
1036
1037 modem_class->grab_port = grab_port;
1038 }
1039
1040 static void
1041 modem_simple_init (MMModemSimple *class)
1042 {
1043 class->connect = simple_connect;
1044 }
1045
1046 static void
1047 modem_gsm_network_init (MMModemGsmNetwork *class)
1048 {
1049 class->set_band = set_band;
1050 class->get_band = get_band;
1051 }
1052
1053 static void
1054 mm_modem_samsung_gsm_init (MMModemSamsungGsm *self)
1055 {
1056 }
1057
1058 static void
1059 mm_modem_samsung_gsm_class_init (MMModemSamsungGsmClass *klass)
1060 {
1061
1062 GObjectClass *object_class = G_OBJECT_CLASS (klass);
1063
1064 MMGenericGsmClass *gsm_class = MM_GENERIC_GSM_CLASS (klass);
1065
1066 mm_modem_samsung_gsm_parent_class = g_type_class_peek_parent (klass);
1067
1068 g_type_class_add_private (object_class, sizeof (MMModemSamsungGsmPrivate));
1069
1070 gsm_class->do_disconnect = do_disconnect;
1071 gsm_class->do_enable = do_enable;
1072
1073 gsm_class->set_allowed_mode = set_allowed_mode;
1074 gsm_class->get_allowed_mode = get_allowed_mode;
1075 gsm_class->get_access_technology = get_access_technology;
1076 }
OLDNEW
« no previous file with comments | « plugins/mm-modem-samsung-gsm.h ('k') | plugins/mm-plugin-samsung.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698