From c0c8954828788033ad43f07d7915101378ee2605 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 10 Mar 2010 15:45:50 -0800 Subject: [PATCH 1/6] gsm: fix PUK2 and other PIN unlock code recognition Longer entries first so we catch them before matching shorter substrings. Previously, the strcmp() would have treated PUK2 and PUK unlocks the same. --- src/mm-generic-gsm.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/mm-generic-gsm.c b/src/mm-generic-gsm.c index dcb37c32..3cc0f566 100644 --- a/src/mm-generic-gsm.c +++ b/src/mm-generic-gsm.c @@ -156,21 +156,22 @@ typedef struct { } CPinResult; static CPinResult unlock_results[] = { - { "SIM PIN", "sim-pin", MM_MOBILE_ERROR_SIM_PIN }, - { "SIM PUK", "sim-puk", MM_MOBILE_ERROR_SIM_PUK }, - { "PH-SIM PIN", "ph-sim-pin", MM_MOBILE_ERROR_PH_SIM_PIN }, - { "PH-FSIM PIN", "ph-fsim-pin", MM_MOBILE_ERROR_PH_FSIM_PIN }, - { "PH-FSIM PUK", "ph-fsim-puk", MM_MOBILE_ERROR_PH_FSIM_PUK }, - { "SIM PIN2", "sim-pin2", MM_MOBILE_ERROR_SIM_PIN2 }, - { "SIM PUK2", "sim-puk2", MM_MOBILE_ERROR_SIM_PUK2 }, - { "PH-NET PIN", "ph-net-pin", MM_MOBILE_ERROR_NETWORK_PIN }, - { "PH-NET PUK", "ph-net-puk", MM_MOBILE_ERROR_NETWORK_PUK }, + /* Longer entries first so we catch the correct one with strcmp() */ { "PH-NETSUB PIN", "ph-netsub-pin", MM_MOBILE_ERROR_NETWORK_SUBSET_PIN }, { "PH-NETSUB PUK", "ph-netsub-puk", MM_MOBILE_ERROR_NETWORK_SUBSET_PUK }, - { "PH-SP PIN", "ph-sp-pin", MM_MOBILE_ERROR_SERVICE_PIN }, - { "PH-SP PUK", "ph-sp-puk", MM_MOBILE_ERROR_SERVICE_PUK }, + { "PH-FSIM PIN", "ph-fsim-pin", MM_MOBILE_ERROR_PH_FSIM_PIN }, + { "PH-FSIM PUK", "ph-fsim-puk", MM_MOBILE_ERROR_PH_FSIM_PUK }, { "PH-CORP PIN", "ph-corp-pin", MM_MOBILE_ERROR_CORP_PIN }, { "PH-CORP PUK", "ph-corp-puk", MM_MOBILE_ERROR_CORP_PUK }, + { "PH-SIM PIN", "ph-sim-pin", MM_MOBILE_ERROR_PH_SIM_PIN }, + { "PH-NET PIN", "ph-net-pin", MM_MOBILE_ERROR_NETWORK_PIN }, + { "PH-NET PUK", "ph-net-puk", MM_MOBILE_ERROR_NETWORK_PUK }, + { "PH-SP PIN", "ph-sp-pin", MM_MOBILE_ERROR_SERVICE_PIN }, + { "PH-SP PUK", "ph-sp-puk", MM_MOBILE_ERROR_SERVICE_PUK }, + { "SIM PIN2", "sim-pin2", MM_MOBILE_ERROR_SIM_PIN2 }, + { "SIM PUK2", "sim-puk2", MM_MOBILE_ERROR_SIM_PUK2 }, + { "SIM PIN", "sim-pin", MM_MOBILE_ERROR_SIM_PIN }, + { "SIM PUK", "sim-puk", MM_MOBILE_ERROR_SIM_PUK }, { NULL, NULL, MM_MOBILE_ERROR_PHONE_FAILURE }, }; From 8f50dd319189c0a9aef4d41957450096029f4b60 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 10 Mar 2010 15:56:27 -0800 Subject: [PATCH 2/6] gsm: close open ports on Enable errors --- src/mm-generic-gsm.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/mm-generic-gsm.c b/src/mm-generic-gsm.c index 3cc0f566..e9100b34 100644 --- a/src/mm-generic-gsm.c +++ b/src/mm-generic-gsm.c @@ -665,11 +665,18 @@ mm_generic_gsm_enable_complete (MMGenericGsm *self, g_return_if_fail (MM_IS_GENERIC_GSM (self)); g_return_if_fail (info != NULL); + priv = MM_GENERIC_GSM_GET_PRIVATE (self); + if (error) { mm_modem_set_state (MM_MODEM (self), MM_MODEM_STATE_DISABLED, MM_MODEM_STATE_REASON_NONE); + if (priv->primary && mm_serial_port_is_open (priv->primary)) + mm_serial_port_close (priv->primary); + if (priv->secondary && mm_serial_port_is_open (priv->secondary)) + mm_serial_port_close (priv->secondary); + info->error = g_error_copy (error); mm_callback_info_schedule (info); return; @@ -678,8 +685,6 @@ mm_generic_gsm_enable_complete (MMGenericGsm *self, mm_generic_gsm_update_enabled_state (self, FALSE, MM_MODEM_STATE_REASON_NONE); } - priv = MM_GENERIC_GSM_GET_PRIVATE (self); - /* Open the second port here if the modem has one. We'll use it for * signal strength and registration updates when the device is connected, * but also many devices will send unsolicited registration or other From 13bc593a291a5bb5ff004b553268443b5d2c83aa Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 10 Mar 2010 16:30:58 -0800 Subject: [PATCH 3/6] gsm: ensure PDP context deactivation happens on disconnect The port is still connected until disconnect_done() runs, but by this point we already know it's been disconnected so it's safe to run the CGACT commands. --- src/mm-generic-gsm.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/mm-generic-gsm.c b/src/mm-generic-gsm.c index e9100b34..cab564ae 100644 --- a/src/mm-generic-gsm.c +++ b/src/mm-generic-gsm.c @@ -1966,13 +1966,19 @@ disconnect_flash_done (MMSerialPort *port, char *command; info->error = mm_modem_check_removed (info->modem, error); - if (info->error) { + /* Ignore NO_CARRIER errors and proceed with the PDP context deactivation */ + if ( info->error + && !g_error_matches (info->error, + MM_MODEM_CONNECT_ERROR, + MM_MODEM_CONNECT_ERROR_NO_CARRIER)) { mm_callback_info_schedule (info); return; } - /* Disconnect the PDP context */ priv = MM_GENERIC_GSM_GET_PRIVATE (info->modem); + mm_port_set_connected (priv->data, FALSE); + + /* Disconnect the PDP context */ if (priv->cid >= 0) command = g_strdup_printf ("+CGACT=0,%d", priv->cid); else { @@ -1980,7 +1986,7 @@ disconnect_flash_done (MMSerialPort *port, command = g_strdup_printf ("+CGACT=0"); } - mm_serial_port_queue_command (port, command, 60, disconnect_cgact_done, info); + mm_serial_port_queue_command (port, command, 3, disconnect_cgact_done, info); g_free (command); } From 79aef47b25dcf33ff9ff49d6f0962a8ee32d73d4 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 11 Mar 2010 10:22:37 -0800 Subject: [PATCH 4/6] api: clarify registration info items --- introspection/mm-modem-gsm-network.xml | 47 ++++++++++++++++++++++---- 1 file changed, 40 insertions(+), 7 deletions(-) diff --git a/introspection/mm-modem-gsm-network.xml b/introspection/mm-modem-gsm-network.xml index 2922b6c6..dd4d1cf7 100644 --- a/introspection/mm-modem-gsm-network.xml +++ b/introspection/mm-modem-gsm-network.xml @@ -118,10 +118,30 @@ - The returned information contains: - * Network status. - * Current operator code. - * Current operator name, + The returned information is composed of the following items in the + following order: +
    +
  • + Mobile registration status as defined in 3GPP TS 27.007 section + 10.1.19. See the MM_MODEM_GSM_NETWORK_REG_STATUS enumeration for + possible values. +
  • +
  • + Current operator code of the operator to which the mobile is + currently registered. Returned in the format "MCCMNC", where MCC + is the three-digit ITU E.212 Mobile Country Code and MNC is the + two- or three-digit GSM Mobile Network Code. If the MCC and MNC + are not known or the mobile is not registered to a mobile network, + this value should be a zero-length (blank) string. e.g. "31026" + or "310260". +
  • +
  • + Current operator name of the operator to which the mobile is + currently registered. If the operator name is not knowon or the + mobile is not registered to a mobile network, this value should + be a zero-length (blank) string. +
  • +
@@ -174,17 +194,27 @@ - The network status. + Mobile registration status as defined in 3GPP TS 27.007 section + 10.1.19. - The current operator code. + Current operator code of the operator to which the mobile is + currently registered. Returned in the format "MCCMNC", where MCC + is the three-digit ITU E.212 Mobile Country Code and MNC is the + two- or three-digit GSM Mobile Network Code. If the MCC and MNC + are not known or the mobile is not registered to a mobile network, + this value should be a zero-length (blank) string. e.g. "31026" or + "310260". - The current operator name. + Current operator name of the operator to which the mobile is + currently registered. If the operator name is not knowon or the + mobile is not registered to a mobile network, this value should + be a zero-length (blank) string. @@ -200,6 +230,9 @@ + + GSM registration code as defined in 3GPP TS 27.007 section 10.1.19. + Not registered, not searching for new operator to register. From c7739979ed4a8be97d03ab7ed0087d63dc218cf4 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 11 Mar 2010 13:15:33 -0800 Subject: [PATCH 5/6] api: update and clarify Location API --- introspection/mm-modem-location.xml | 112 +++++++++++++++++++++++++--- 1 file changed, 101 insertions(+), 11 deletions(-) diff --git a/introspection/mm-modem-location.xml b/introspection/mm-modem-location.xml index dfcf9dee..9d3b265e 100644 --- a/introspection/mm-modem-location.xml +++ b/introspection/mm-modem-location.xml @@ -26,7 +26,9 @@ Enable or disable location information gathering. This method may - require the client to authenticate itself. + require the client to authenticate itself. This method may also cause + any necessary functionality of the mobile be be turned on, including + enabling the modem device itself. @@ -92,28 +94,116 @@ - Identifies the type and format of the associated location information. Contrary to the value description, this is not a bitfield but uses the same values as the MM_MODEM_LOCATION_CAPABILITIES bitfield. + Identifies the type and format of the associated location information. + Contrary to the value description, this is not a bitfield but uses the + same values as the MM_MODEM_LOCATION_CAPABILITIES bitfield. - Contains type-specific location information. GSM_LAC_CI data is a string with the format "LAC,CI" (ex "84CD,00D30156") while GPS_NMEA is a string in NMEA-compatible format. + Contains type-specific location information. See the documentation for + each type for a description of its data format. - Unknown or no capabilties. +

Unknown or no capabilties.

- - Reserved. + + +

For capability reporting, indicates the device is capable of + providing GPS NMEA-format location information.

+ +

For location reporting, devices supporting this capability return + an array mapping timestamps to specific NMEA sentences (D-Bus + signature 'a(ss)'). The manager will cache the most recent NMEA + sentence of each type for a period of time not less than 30 seconds + and must indicate the time that sentence was receieved from the device + using the timestamp. Timestamps are provided as strings in the "Unix + epoch" format (i.e. number of seconds since 1970-01-01 00:00:00 UTC + with microsecond resolution if available). +

+

+ For example, if at time 1268336242.282202 the device sends a $GPRMC + sentence immediately followed by a $GPGGA sentence, the reported + location array would be: +

+          [ '1268336242.282202': '$GPRMC,134523.92,V,,,,,,,030136,,,N*73',
+            '1268336242.282202': '$GPGGA,,,,,,0,00,0.5,,M,0.0001999,M,0.0000099,0000*45' ]
+          
+ If the device sends a new $GPRMC three seconds later, the new $GPRMC + replaces the previously received $GPRMC sentence, and the updated array + would be: +
+          [ '1268336245.282202': '$GPRMC,134526.92,V,,,,,,,030136,,,N*76',
+            '1268336242.282202': '$GPGGA,,,,,,0,00,0.5,,M,0.0001999,M,0.0000099,0000*45' ]
+          
+ If the device then sends a $GPGSA sentence about 5 seconds later, the + $GPGSA sentence is added to the array (since no $GPGSA sentence was + previously received in this session), the updated array would be: +
+          [ '1268336245.282202': '$GPRMC,134526.92,V,,,,,,,030136,,,N*76',
+            '1268336242.282202': '$GPGGA,,,,,,0,00,0.5,,M,0.0001999,M,0.0000099,0000*45'
+            '1268336250.395423': '$GPGSA,A,1,,,,,,,,,,,,,1.1,0.5,1.0*34' ]
+          
+ The manager may discard any entries older than 30 seconds. +

+

This allows clients to read the latest positioning data as soon as + possible after they start, even if the device is not providing + frequent location data updates. Using the timestamp the client can + determine which data is most relevant to its particular uses. +

+
- - The device is capable of providing GPS NMEA-format location information. - - - The device is capable of providing GSM Location Area Code/Cell ID location information. + + +

For capability reporting, indicates the device is capable of + providing GSM Location Area Code/Cell ID location information.

+ +

For location reporting, devices supporting this + capability return a string in the format "MCC,MNC,LAC,CI" (without the + quotes of course) where the following applies:

+
    +
  • + MCC is the three-digit ITU E.212 Mobile Country Code of the + network provider to which the mobile is currently registered. + This value should be the same MCC as reported by the + org.freedesktop.Modem.Gsm.Network.GetRegistrationInfo() method's + returned "operator code" argument. + e.g. "310" +
  • +
  • + MNC is the two- or three-digit GSM Mobile Network Code of the + network provider to which the mobile is currently registered. + This value should be the same MCC as reported by the + org.freedesktop.Modem.Gsm.Network.GetRegistrationInfo() method's + returned "operator code" argument. + e.g. "26" or "260" +
  • +
  • + LAC is the two-byte Location Area Code of the base station with + which the mobile is registered, in upper-case hexadecimal format + without leading zeros, as specified in 3GPP TS 27.007 section + 10.1.19. e.g. "84CD". +
  • +
  • + CI is the two- or four-byte Cell Identifier with which the mobile + is registered, in upper-case hexadecimal format without leading + zeros, as specified in 3GPP TS 27.007. e.g. "2BAF" or "D30156". +
  • +
+

The entire string may only be composed of the ASCII digits [0-9], + the alphabetical characters [A-F], and the comma (,) character. No + other characters are allowed. For example: "310,260,8BE3,2BAF" or + "250,40,CE00,1CEAD8F0".

+ +

If any of these four items (MCC,MNC,LAC,CI) is unknown or the + mobile is not registered with a network, then the GSM_LAC_CI location + information item should not be provided as a returned value from the + GetLocation() method or in the Location property.

+
From 749f9c0eb569b29772dde9561b9856e4f878d9ef Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 11 Mar 2010 13:20:43 -0800 Subject: [PATCH 6/6] core: stop probing known-unusable ports early Some ports we know we shouldn't use when we get certain responses from them. Reading from these ports triggers kernel bugs (at least on 2.6.31 and 2.6.32) relating to flow control in some drivers (*cough* hso *cough*), so lets try not to aggravate the kernel too much. This happens on Icera-based Option devices like the GI0322 (AT&T Quicksilver) for example. (note: AFAICT this doesn't have any relation to the recent XON/XOFF patch, since I get this problem without the XON/XOFF patch on both 2.6.31 and 2.6.32 as well) --- BUG: sleeping function called from invalid context at kernel/mutex.c:94 in_atomic(): 1, irqs_disabled(): 1, pid: 9295, name: modem-manager Pid: 9295, comm: modem-manager Not tainted 2.6.32.9-67.fc12.x86_64 #1 Call Trace: [] __might_sleep+0xed/0xef [] mutex_lock+0x24/0x50 [] ? enqueue_task_fair+0x2a/0x6d [] tty_throttle+0x1b/0x49 [] n_tty_receive_buf+0xdbb/0xe12 [] ? task_rq_unlock+0x11/0x13 [] ? try_to_wake_up+0x2f3/0x305 [] ? __kmalloc+0x37/0x15e [] ? __kmalloc+0x6d/0x15e [] flush_to_ldisc+0xf8/0x18d [] tty_flip_buffer_push+0x50/0x61 [] put_rxbuf_data+0xea/0x124 [hso] [] put_rxbuf_data_and_resubmit_bulk_urb+0x21/0x6b [hso] [] hso_std_serial_read_bulk_callback+0x14d/0x15f [hso] [] ? dma_unmap_single_attrs.clone.0+0x38/0x3a [] usb_hcd_giveback_urb+0x91/0xc5 [] ehci_urb_done+0x7b/0x90 [] ? try_to_wake_up+0x2f3/0x305 [] qh_completions+0x368/0x4b9 [] ? __wake_up_common+0x4e/0x84 [] ehci_work+0x95/0x732 [] ? __wake_up+0x44/0x4d [] ? insert_work+0x8e/0x9b [] ehci_irq+0x2be/0x420 [] ? __queue_work+0x3a/0x41 [] ? resched_cpu+0x6e/0x77 [] ? delayed_work_timer_fn+0x3c/0x3e [] ? __rcu_process_callbacks+0x7d/0x28a [] usb_hcd_irq+0x3f/0x7b [] handle_IRQ_event+0x60/0x121 [] handle_fasteoi_irq+0x8b/0xc7 [] handle_irq+0x8b/0x96 [] do_IRQ+0x5c/0xbc [] ret_from_intr+0x0/0x11 --- src/mm-plugin-base.c | 55 +++++++++++++++++++++++++++++++++++++++++++- src/mm-serial-port.c | 29 +++++++++++++++++------ src/mm-serial-port.h | 3 +++ 3 files changed, 79 insertions(+), 8 deletions(-) diff --git a/src/mm-plugin-base.c b/src/mm-plugin-base.c index 202eaac9..4b74feb7 100644 --- a/src/mm-plugin-base.c +++ b/src/mm-plugin-base.c @@ -77,6 +77,8 @@ typedef enum { PROBE_STATE_LAST } ProbeState; +static void probe_complete (MMPluginBaseSupportsTask *task); + /*****************************************************************************/ G_DEFINE_TYPE (MMPluginBaseSupportsTask, mm_plugin_base_supports_task, G_TYPE_OBJECT) @@ -91,6 +93,7 @@ typedef struct { guint open_id; guint32 open_tries; + guint full_id; MMSerialPort *probe_port; guint32 probed_caps; @@ -198,6 +201,11 @@ mm_plugin_base_supports_task_complete (MMPluginBaseSupportsTask *task, priv = MM_PLUGIN_BASE_SUPPORTS_TASK_GET_PRIVATE (task); g_return_if_fail (priv->callback != NULL); + if (priv->full_id) { + g_source_remove (priv->full_id); + priv->full_id = 0; + } + subsys = g_udev_device_get_subsystem (priv->port); name = g_udev_device_get_name (priv->port); @@ -251,11 +259,15 @@ supports_task_dispose (GObject *object) if (priv->open_id) g_source_remove (priv->open_id); + if (priv->full_id) + g_source_remove (priv->full_id); if (priv->probe_id) g_source_remove (priv->probe_id); - if (priv->probe_port) + if (priv->probe_port) { + mm_serial_port_close (priv->probe_port); g_object_unref (priv->probe_port); + } G_OBJECT_CLASS (mm_plugin_base_supports_task_parent_class)->dispose (object); } @@ -349,6 +361,44 @@ parse_cgmm (const char *buf) return 0; } +static const char *dq_strings[] = { + "option/faema_", "os_logids.h", NULL +}; + +static void +port_buffer_full (MMSerialPort *port, GString *buffer, gpointer user_data) +{ + MMPluginBaseSupportsTask *task = MM_PLUGIN_BASE_SUPPORTS_TASK (user_data); + MMPluginBaseSupportsTaskPrivate *priv = MM_PLUGIN_BASE_SUPPORTS_TASK_GET_PRIVATE (user_data); + const char **iter; + size_t iter_len; + int i; + + /* Check for an immediate disqualification response. There are some + * ports (Option Icera-based chipsets have them, as do Qualcomm Gobi + * devices before their firmware is loaded) that just shouldn't be + * probed if we get a certain response because we know they can't be + * used. Kernel bugs (at least with 2.6.31 and 2.6.32) also trigger port + * flow control kernel oopses if we read too much data for these ports. + */ + + for (iter = &dq_strings[0]; iter && *iter; iter++) { + /* Search in the response for the item; the response could have embedded + * nulls so we can't use memcmp() or strstr() on the whole response. + */ + iter_len = strlen (*iter); + for (i = 0; i < buffer->len - iter_len; i++) { + if (!memcmp (&buffer->str[i], *iter, iter_len)) { + /* Immediately close the port and complete probing */ + priv->probed_caps = 0; + mm_serial_port_close (priv->probe_port); + probe_complete (task); + return; + } + } + } +} + static gboolean emit_probe_result (gpointer user_data) { @@ -626,6 +676,9 @@ try_open (gpointer user_data) port = mm_plugin_base_supports_task_get_port (task); g_assert (port); + task_priv->full_id = g_signal_connect (task_priv->probe_port, "buffer-full", + G_CALLBACK (port_buffer_full), task); + g_debug ("(%s): probe requested by plugin '%s'", g_udev_device_get_name (port), mm_plugin_get_name (MM_PLUGIN (task_priv->plugin))); diff --git a/src/mm-serial-port.c b/src/mm-serial-port.c index 1d98a537..2134751f 100644 --- a/src/mm-serial-port.c +++ b/src/mm-serial-port.c @@ -730,9 +730,13 @@ data_available (GIOChannel *source, status = g_io_channel_read_chars (source, buf, SERIAL_BUF_SIZE, &bytes_read, &err); if (status == G_IO_STATUS_ERROR) { - g_warning ("%s", err->message); - g_error_free (err); - err = NULL; + if (err && err->message) + g_warning ("%s", err->message); + g_clear_error (&err); + + /* Serial port is closed; we're done */ + if (priv->watch_id == 0) + break; } /* If no bytes read, just let g_io_channel wait for more data */ @@ -745,10 +749,10 @@ data_available (GIOChannel *source, } /* Make sure the string doesn't grow too long */ - if (priv->response->len > SERIAL_BUF_SIZE) { - g_warning ("%s (%s): response buffer filled before repsonse received", - G_STRFUNC, mm_port_get_device (MM_PORT (self))); - g_string_erase (priv->response, 0, (SERIAL_BUF_SIZE / 2)); + if (priv->response->len > SERIAL_BUF_SIZE) { + /* Notify listeners and then trim the buffer */ + g_signal_emit_by_name (self, "buffer-full", priv->response); + g_string_erase (priv->response, 0, (SERIAL_BUF_SIZE / 2)); } if (parse_response (self, priv->response, &err)) @@ -888,6 +892,7 @@ mm_serial_port_close (MMSerialPort *self) if (priv->channel) { g_source_remove (priv->watch_id); + priv->watch_id = 0; g_io_channel_shutdown (priv->channel, TRUE, NULL); g_io_channel_unref (priv->channel); priv->channel = NULL; @@ -1293,4 +1298,14 @@ mm_serial_port_class_init (MMSerialPortClass *klass) "Send delay", 0, G_MAXUINT64, 0, G_PARAM_READWRITE)); + + /* Signals */ + g_signal_new ("buffer-full", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (MMSerialPortClass, buffer_full), + NULL, NULL, + g_cclosure_marshal_VOID__POINTER, + G_TYPE_NONE, 1, G_TYPE_POINTER); } + diff --git a/src/mm-serial-port.h b/src/mm-serial-port.h index a2697f30..dd5a6689 100644 --- a/src/mm-serial-port.h +++ b/src/mm-serial-port.h @@ -62,6 +62,9 @@ struct _MMSerialPort { struct _MMSerialPortClass { MMPortClass parent; + + /* Signals */ + void (*buffer_full) (MMSerialPort *port, const GString *buffer); }; GType mm_serial_port_get_type (void);