6
6
7
7
#include "config.h"
8
8
9
+ #ifdef HAVE_TERMIOS_H
10
+ #include <termios.h>
11
+ #endif
12
+
9
13
#include "fu-mm-common.h"
10
14
#include "fu-mm-device.h"
11
15
20
24
/* not strictly last, but the last we care about */
21
25
#define MM_MODEM_PORT_TYPE_LAST (MM_MODEM_PORT_TYPE_IGNORED + 1)
22
26
27
+ typedef enum {
28
+ FU_MM_DEVICE_PORT_FLAG_NONE = 0 ,
29
+ FU_MM_DEVICE_PORT_FLAG_MAKE_RAW = 1 << 0 ,
30
+ } FuMmDevicePortFlags ;
31
+
32
+ typedef struct {
33
+ MMModemPortType type ;
34
+ gchar * device_file ;
35
+ FuMmDevicePortFlags flags ;
36
+ } FuMmDevicePort ;
37
+
23
38
typedef struct {
24
39
gboolean inhibited ;
25
40
gchar * branch_at ;
26
41
gchar * inhibition_uid ;
27
- gchar * port [ MM_MODEM_PORT_TYPE_LAST ];
42
+ GPtrArray * ports ; /* element-type FuMmDevicePort */
28
43
} FuMmDevicePrivate ;
29
44
30
45
G_DEFINE_TYPE_WITH_PRIVATE (FuMmDevice , fu_mm_device , FU_TYPE_UDEV_DEVICE );
@@ -37,6 +52,13 @@ G_DEFINE_TYPE_WITH_PRIVATE(FuMmDevice, fu_mm_device, FU_TYPE_UDEV_DEVICE);
37
52
38
53
enum { PROP_0 , PROP_INHIBITED , PROP_LAST };
39
54
55
+ static void
56
+ fu_mm_device_port_free (FuMmDevicePort * port )
57
+ {
58
+ g_free (port -> device_file );
59
+ g_free (port );
60
+ }
61
+
40
62
static void
41
63
fu_mm_device_set_branch_at (FuMmDevice * self , const gchar * branch_at )
42
64
{
@@ -55,12 +77,11 @@ fu_mm_device_to_string(FuDevice *device, guint idt, GString *str)
55
77
fwupd_codec_string_append (str , idt , "BranchAt" , priv -> branch_at );
56
78
fwupd_codec_string_append_bool (str , idt , "Inhibited" , priv -> inhibited );
57
79
fwupd_codec_string_append (str , idt , "InhibitionUid" , priv -> inhibition_uid );
58
- for (guint i = 0 ; i < MM_MODEM_PORT_TYPE_LAST ; i ++ ) {
59
- if (priv -> port [i ] != NULL ) {
60
- g_autofree gchar * title =
61
- g_strdup_printf ("Port[%s]" , fu_mm_device_port_type_to_string (i ));
62
- fwupd_codec_string_append (str , idt , title , priv -> port [i ]);
63
- }
80
+ for (guint i = 0 ; i < priv -> ports -> len ; i ++ ) {
81
+ FuMmDevicePort * port = g_ptr_array_index (priv -> ports , i );
82
+ g_autofree gchar * title =
83
+ g_strdup_printf ("Port[%s]" , fu_mm_device_port_type_to_string (port -> type ));
84
+ fwupd_codec_string_append (str , idt , title , port -> device_file );
64
85
}
65
86
}
66
87
@@ -96,17 +117,27 @@ fu_mm_device_set_device_file(FuMmDevice *self, MMModemPortType port_type, GError
96
117
{
97
118
FuMmDevicePrivate * priv = GET_PRIVATE (self );
98
119
g_return_val_if_fail (FU_IS_MM_DEVICE (self ), FALSE);
99
- g_return_val_if_fail (port_type < MM_MODEM_PORT_TYPE_LAST , FALSE);
100
- if (priv -> port [port_type ] == NULL ) {
101
- g_set_error (error ,
102
- FWUPD_ERROR ,
103
- FWUPD_ERROR_NOT_SUPPORTED ,
104
- "no port for %s" ,
105
- fu_mm_device_port_type_to_string (port_type ));
106
- return FALSE;
120
+
121
+ /* find port by type */
122
+ for (guint i = 0 ; i < priv -> ports -> len ; i ++ ) {
123
+ FuMmDevicePort * port = g_ptr_array_index (priv -> ports , i );
124
+ if (port_type == port -> type ) {
125
+ if (port -> flags & FU_MM_DEVICE_PORT_FLAG_MAKE_RAW ) {
126
+ fu_device_add_private_flag (FU_DEVICE (self ),
127
+ FU_MM_DEVICE_FLAG_MAKE_SERIAL_RAW );
128
+ }
129
+ fu_udev_device_set_device_file (FU_UDEV_DEVICE (self ), port -> device_file );
130
+ return TRUE;
131
+ }
107
132
}
108
- fu_udev_device_set_device_file (FU_UDEV_DEVICE (self ), priv -> port [port_type ]);
109
- return TRUE;
133
+
134
+ /* not found */
135
+ g_set_error (error ,
136
+ FWUPD_ERROR ,
137
+ FWUPD_ERROR_NOT_SUPPORTED ,
138
+ "no port for %s" ,
139
+ fu_mm_device_port_type_to_string (port_type ));
140
+ return FALSE;
110
141
}
111
142
112
143
static gboolean
@@ -310,14 +341,30 @@ fu_mm_device_add_instance_id(FuMmDevice *self, const gchar *device_id, GError **
310
341
}
311
342
312
343
static void
313
- fu_mm_device_add_port (FuMmDevice * self , MMModemPortType port_type , const gchar * device_file )
344
+ fu_mm_device_add_port (FuMmDevice * self ,
345
+ MMModemPortType port_type ,
346
+ const gchar * device_file ,
347
+ FuMmDevicePortFlags flags )
314
348
{
315
349
FuMmDevicePrivate * priv = GET_PRIVATE (self );
350
+ FuMmDevicePort * port ;
351
+
316
352
if (port_type >= MM_MODEM_PORT_TYPE_LAST )
317
353
return ;
318
- if (priv -> port [port_type ] != NULL )
319
- return ;
320
- priv -> port [port_type ] = g_strdup (device_file );
354
+
355
+ /* already exists */
356
+ for (guint i = 0 ; i < priv -> ports -> len ; i ++ ) {
357
+ port = g_ptr_array_index (priv -> ports , i );
358
+ if (port -> type == port_type )
359
+ return ;
360
+ }
361
+
362
+ /* create new */
363
+ port = g_new0 (FuMmDevicePort , 1 );
364
+ port -> type = port_type ;
365
+ port -> flags = flags ;
366
+ port -> device_file = g_strdup (device_file );
367
+ g_ptr_array_add (priv -> ports , port );
321
368
}
322
369
323
370
gboolean
@@ -389,9 +436,15 @@ fu_mm_device_probe_from_omodem(FuMmDevice *self, MMObject *omodem, GError **erro
389
436
continue ;
390
437
if (used_ports [i ].type == MM_MODEM_PORT_TYPE_IGNORED &&
391
438
g_pattern_match_simple ("wwan*qcdm*" , used_ports [i ].name )) {
392
- fu_mm_device_add_port (self , MM_MODEM_PORT_TYPE_QCDM , device_file );
439
+ fu_mm_device_add_port (self ,
440
+ MM_MODEM_PORT_TYPE_QCDM ,
441
+ device_file ,
442
+ FU_MM_DEVICE_PORT_FLAG_NONE );
393
443
} else {
394
- fu_mm_device_add_port (self , used_ports [i ].type , device_file );
444
+ fu_mm_device_add_port (self ,
445
+ used_ports [i ].type ,
446
+ device_file ,
447
+ FU_MM_DEVICE_PORT_FLAG_NONE );
395
448
}
396
449
}
397
450
mm_modem_port_info_array_free (used_ports , n_used_ports );
@@ -408,8 +461,10 @@ fu_mm_device_probe_from_omodem(FuMmDevice *self, MMObject *omodem, GError **erro
408
461
g_autofree gchar * device_file = g_strdup_printf ("/dev/%s" , ignored_ports [i ].name );
409
462
if (ignored_ports [i ].type >= MM_MODEM_PORT_TYPE_LAST )
410
463
continue ;
411
-
412
- fu_mm_device_add_port (self , ignored_ports [i ].type , device_file );
464
+ fu_mm_device_add_port (self ,
465
+ ignored_ports [i ].type ,
466
+ device_file ,
467
+ FU_MM_DEVICE_PORT_FLAG_MAKE_RAW );
413
468
}
414
469
mm_modem_port_info_array_free (ignored_ports , n_ignored_ports );
415
470
#endif // MM_CHECK_VERSION(1, 26, 0)
@@ -686,6 +741,70 @@ fu_mm_device_ensure_payload(FuMmDevice *self)
686
741
}
687
742
}
688
743
744
+ static gboolean
745
+ fu_mm_device_make_serial_raw (FuMmDevice * self , GError * * error )
746
+ {
747
+ #ifdef HAVE_TERMIOS_H
748
+ gint fd = fu_io_channel_unix_get_fd (fu_udev_device_get_io_channel (FU_UDEV_DEVICE (self )));
749
+ struct termios tio ;
750
+
751
+ if (tcgetattr (fd , & tio ) != 0 ) {
752
+ g_set_error (error ,
753
+ FWUPD_ERROR ,
754
+ #ifdef HAVE_ERRNO_H
755
+ g_io_error_from_errno (errno ),
756
+ #else
757
+ G_IO_ERROR_FAILED , /* nocheck:blocked */
758
+ #endif
759
+ "could not get termios attributes: %s" ,
760
+ fwupd_strerror (errno ));
761
+ return FALSE;
762
+ }
763
+
764
+ cfmakeraw (& tio );
765
+
766
+ if (tcsetattr (fd , TCSANOW , & tio ) != 0 ) {
767
+ g_set_error (error ,
768
+ FWUPD_ERROR ,
769
+ #ifdef HAVE_ERRNO_H
770
+ g_io_error_from_errno (errno ),
771
+ #else
772
+ G_IO_ERROR_FAILED , /* nocheck:blocked */
773
+ #endif
774
+ "could not set termios attributes: %s" ,
775
+ fwupd_strerror (errno ));
776
+ return FALSE;
777
+ }
778
+
779
+ return TRUE;
780
+ #else
781
+ g_set_error_literal (error ,
782
+ FWUPD_ERROR ,
783
+ FWUPD_ERROR_NOT_SUPPORTED ,
784
+ "Not supported as <termios.h> not found" );
785
+ return FALSE;
786
+ #endif
787
+ }
788
+
789
+ static gboolean
790
+ fu_mm_device_open (FuDevice * device , GError * * error )
791
+ {
792
+ FuMmDevice * self = FU_MM_DEVICE (device );
793
+
794
+ /* FuUdevDevice->open() */
795
+ if (!FU_DEVICE_CLASS (fu_mm_device_parent_class )-> open (device , error ))
796
+ return FALSE;
797
+
798
+ /* ignored ports have not previously been configured by ModemManager */
799
+ if (fu_device_has_private_flag (device , FU_MM_DEVICE_FLAG_MAKE_SERIAL_RAW )) {
800
+ if (!fu_mm_device_make_serial_raw (self , error ))
801
+ return FALSE;
802
+ }
803
+
804
+ /* success */
805
+ return TRUE;
806
+ }
807
+
689
808
static gboolean
690
809
fu_mm_device_setup (FuDevice * device , GError * * error )
691
810
{
@@ -757,7 +876,8 @@ fu_mm_device_from_json(FuDevice *device, JsonObject *json_object, GError **error
757
876
const gchar * port_type = l -> data ;
758
877
fu_mm_device_add_port (self ,
759
878
fu_mm_device_port_type_from_string (port_type ),
760
- json_object_get_string_member (json_ports , port_type ));
879
+ json_object_get_string_member (json_ports , port_type ),
880
+ FU_MM_DEVICE_PORT_FLAG_NONE );
761
881
}
762
882
}
763
883
@@ -808,12 +928,11 @@ fu_mm_device_add_json(FuDevice *device, JsonBuilder *builder, FwupdCodecFlags fl
808
928
/* ports always specified */
809
929
json_builder_set_member_name (builder , "Ports" );
810
930
json_builder_begin_object (builder );
811
- for (guint i = 0 ; i < MM_MODEM_PORT_TYPE_LAST ; i ++ ) {
812
- if (priv -> port [i ] != NULL ) {
813
- fwupd_codec_json_append (builder ,
814
- fu_mm_device_port_type_to_string (i ),
815
- priv -> port [i ]);
816
- }
931
+ for (guint i = 0 ; i < priv -> ports -> len ; i ++ ) {
932
+ FuMmDevicePort * port = g_ptr_array_index (priv -> ports , i );
933
+ fwupd_codec_json_append (builder ,
934
+ fu_mm_device_port_type_to_string (port -> type ),
935
+ port -> device_file );
817
936
}
818
937
json_builder_end_object (builder );
819
938
}
@@ -850,6 +969,7 @@ fu_mm_device_set_property(GObject *object, guint prop_id, const GValue *value, G
850
969
static void
851
970
fu_mm_device_init (FuMmDevice * self )
852
971
{
972
+ FuMmDevicePrivate * priv = GET_PRIVATE (self );
853
973
fu_device_add_flag (FU_DEVICE (self ), FWUPD_DEVICE_FLAG_UPDATABLE );
854
974
fu_device_add_flag (FU_DEVICE (self ), FWUPD_DEVICE_FLAG_REQUIRE_AC );
855
975
fu_device_set_firmware_gtype (FU_DEVICE (self ), FU_TYPE_ARCHIVE_FIRMWARE );
@@ -862,9 +982,11 @@ fu_mm_device_init(FuMmDevice *self)
862
982
fu_device_set_summary (FU_DEVICE (self ), "Mobile broadband device" );
863
983
fu_device_add_icon (FU_DEVICE (self ), FU_DEVICE_ICON_MODEM );
864
984
fu_device_register_private_flag (FU_DEVICE (self ), FU_MM_DEVICE_FLAG_USE_BRANCH );
985
+ fu_device_register_private_flag (FU_DEVICE (self ), FU_MM_DEVICE_FLAG_MAKE_SERIAL_RAW );
865
986
fu_device_add_possible_plugin (FU_DEVICE (self ), "modem_manager" );
866
987
fu_udev_device_add_open_flag (FU_UDEV_DEVICE (self ), FU_IO_CHANNEL_OPEN_FLAG_READ );
867
988
fu_udev_device_add_open_flag (FU_UDEV_DEVICE (self ), FU_IO_CHANNEL_OPEN_FLAG_WRITE );
989
+ priv -> ports = g_ptr_array_new_with_free_func ((GDestroyNotify )fu_mm_device_port_free );
868
990
}
869
991
870
992
static void
@@ -873,10 +995,9 @@ fu_mm_device_finalize(GObject *object)
873
995
FuMmDevice * self = FU_MM_DEVICE (object );
874
996
FuMmDevicePrivate * priv = GET_PRIVATE (self );
875
997
876
- for (guint i = 0 ; i < MM_MODEM_PORT_TYPE_LAST ; i ++ )
877
- g_free (priv -> port [i ]);
878
998
g_free (priv -> branch_at );
879
999
g_free (priv -> inhibition_uid );
1000
+ g_ptr_array_unref (priv -> ports );
880
1001
881
1002
G_OBJECT_CLASS (fu_mm_device_parent_class )-> finalize (object );
882
1003
}
@@ -896,6 +1017,7 @@ fu_mm_device_class_init(FuMmDeviceClass *klass)
896
1017
device_class -> set_quirk_kv = fu_mm_device_set_quirk_kv ;
897
1018
device_class -> from_json = fu_mm_device_from_json ;
898
1019
device_class -> add_json = fu_mm_device_add_json ;
1020
+ device_class -> open = fu_mm_device_open ;
899
1021
900
1022
pspec = g_param_spec_boolean ("inhibited" ,
901
1023
NULL ,
0 commit comments