All of lore.kernel.org
 help / color / mirror / Atom feed
From: Marcel Holtmann <marcel@holtmann.org>
To: ofono@ofono.org
Subject: Re: [RFC PATCH 1/2] Add basic Telit UC864-G support:
Date: Thu, 19 May 2011 10:48:22 -0700	[thread overview]
Message-ID: <1305827302.15916.200.camel@aeonflux> (raw)
In-Reply-To: <1305801624-3410-1-git-send-email-Bernhard.Guillon@hale.at>

[-- Attachment #1: Type: text/plain, Size: 17737 bytes --]

Hi Bernhard,

> *add a basic plugin based on different ofono plugins
> *use Telit specific QSS for SIM-state
> *add verry basic GPS support (usable with gypsy)
> *add udev support and rules
> *update Makefile
> 
> Co-authored-by: Christopher Vogl <Christopher.Vogl@hale.at>
> Signed-off-by: Bernhard Guillon <Bernhard.Guillon@hale.at>

we are not using Signed-off-by for our commits.

> ---
>  Makefile.am              |    3 +
>  drivers/atmodem/vendor.h |    1 +
>  plugins/ofono.rules      |   16 ++-
>  plugins/telit.c          |  387 ++++++++++++++++++++++++++++++++++++++++++++++
>  plugins/udev.c           |   40 +++++
>  5 files changed, 446 insertions(+), 1 deletions(-)
>  create mode 100644 plugins/telit.c

please split changes into three patches. One for drivers, one for udev
(including the rules) and one for the telit modem plugin.

> diff --git a/Makefile.am b/Makefile.am
> index a413a47..6197cf6 100644
> --- a/Makefile.am
> +++ b/Makefile.am
> @@ -326,6 +326,9 @@ builtin_sources += plugins/nokiacdma.c
>  builtin_modules += linktop
>  builtin_sources += plugins/linktop.c
>  
> +builtin_modules += telit
> +builtin_sources += plugins/telit.c
> +
>  if BLUETOOTH
>  builtin_modules += bluetooth
>  builtin_sources += plugins/bluetooth.c plugins/bluetooth.h
> diff --git a/drivers/atmodem/vendor.h b/drivers/atmodem/vendor.h
> index 3898fa8..412bc76 100644
> --- a/drivers/atmodem/vendor.h
> +++ b/drivers/atmodem/vendor.h
> @@ -35,4 +35,5 @@ enum ofono_vendor {
>  	OFONO_VENDOR_WAVECOM,
>  	OFONO_VENDOR_NOKIA,
>  	OFONO_VENDOR_PHONESIM,
> +	OFONO_VENDOR_TELIT,
>  };
> diff --git a/plugins/ofono.rules b/plugins/ofono.rules
> index 5a36380..c0c4360 100644
> --- a/plugins/ofono.rules
> +++ b/plugins/ofono.rules
> @@ -306,7 +306,7 @@ ATTRS{idVendor}=="12d1", ATTRS{idProduct}=="1479", ENV{OFONO_IFACE_NUM}=="00", E
>  ATTRS{idVendor}=="12d1", ATTRS{idProduct}=="1479", ENV{OFONO_IFACE_NUM}=="04", ENV{OFONO_HUAWEI_TYPE}="Pcui"
>  
>  ATTRS{idVendor}=="12d1", ATTRS{idProduct}=="147a", ENV{OFONO_IFACE_NUM}=="00", ENV{OFONO_HUAWEI_TYPE}="Modem"
> -ATTRS{idVendor}=="12d1", ATTRS{idProduct}=="147a", ENV{OFONO_IFACE_NUM}=="04", ENV{OFONO_HUAWEI_TYPE}="Pcui"
> +	ATTRS{idVendor}=="12d1", ATTRS{idProduct}=="147a", ENV{OFONO_IFACE_NUM}=="04", ENV{OFONO_HUAWEI_TYPE}="Pcui"

You are messing with already existing rules here. Please don't.
 
>  ATTRS{idVendor}=="12d1", ATTRS{idProduct}=="147b", ENV{OFONO_IFACE_NUM}=="00", ENV{OFONO_HUAWEI_TYPE}="Modem"
>  ATTRS{idVendor}=="12d1", ATTRS{idProduct}=="147b", ENV{OFONO_IFACE_NUM}=="04", ENV{OFONO_HUAWEI_TYPE}="Pcui"
> @@ -346,6 +346,20 @@ ATTRS{idVendor}=="12d1", ATTRS{idProduct}=="1486", ENV{OFONO_IFACE_NUM}=="02", E
>  
>  LABEL="ofono_tty_end"
>  
> +#Telit
> +#This modem is not in SUBSYSTEM tty but in KERNEL ttyUSB. Therefore it is intended to be
> +#after the ofono_tty_end line

Why is that. What kernel driver is claiming this modem?

> +#UC864-G
> +
> +ATTR{idVendor}=="1bc7", ATTR{idProduct}=="1004", ENV{OFONO_IFACE_NUM}=="00", ENV{OFONO_TELIT_TYPE}="modem"
> +ATTR{idVendor}=="1bc7", ATTR{idProduct}=="1004", ENV{OFONO_IFACE_NUM}=="01", ENV{OFONO_TELIT_TYPE}="aux"
> +ATTR{idVendor}=="1bc7", ATTR{idProduct}=="1004", ENV{OFONO_IFACE_NUM}=="02", ENV{OFONO_TELIT_TYPE}="gps"
> +ATTR{idVendor}=="1bc7", ATTR{idProduct}=="1004", ENV{OFONO_IFACE_NUM}=="03", ENV{OFONO_TELIT_TYPE}="uart"
> +
> +ATTR{idVendor}=="1bc7", ENV{OFONO_DRIVER}="telit"
> +ATTR{idVendor}=="1bc7", ATTR{idProduct}=="1004", ENV{OFONO_TELIT_MODEL}="UC864-G"

Do you really need this model number?

> +
>  # ISI/Phonet drivers
>  SUBSYSTEM!="net", GOTO="ofono_isi_end"
>  ATTRS{type}!="820", GOTO="ofono_isi_end"
> diff --git a/plugins/telit.c b/plugins/telit.c
> new file mode 100644
> index 0000000..d157561
> --- /dev/null
> +++ b/plugins/telit.c
> @@ -0,0 +1,387 @@
> +/*
> + *
> + *  oFono - Open Source Telephony
> + *
> + *  Copyright (C) 2008-2010  Intel Corporation. All rights reserved.
> + *
> + *  This program is free software; you can redistribute it and/or modify
> + *  it under the terms of the GNU General Public License version 2 as
> + *  published by the Free Software Foundation.
> + *
> + *  This program is distributed in the hope that it will be useful,
> + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
> + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + *  GNU General Public License for more details.
> + *
> + *  You should have received a copy of the GNU General Public License
> + *  along with this program; if not, write to the Free Software
> + *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
> + *
> + */
> +
> +#ifdef HAVE_CONFIG_H
> +#include <config.h>
> +#endif
> +
> +#include <errno.h>
> +#include <stdlib.h>
> +#include <stdio.h>
> +#include <unistd.h>
> +
> +#include <glib.h>
> +#include <gatchat.h>
> +#include <gattty.h>
> +
> +#define OFONO_API_SUBJECT_TO_CHANGE
> +#include <ofono/plugin.h>
> +#include <ofono/log.h>
> +#include <ofono/modem.h>
> +#include <ofono/call-barring.h>
> +#include <ofono/call-forwarding.h>
> +#include <ofono/call-meter.h>
> +#include <ofono/call-settings.h>
> +#include <ofono/devinfo.h>
> +#include <ofono/message-waiting.h>
> +#include <ofono/netreg.h>
> +#include <ofono/phonebook.h>
> +#include <ofono/sim.h>
> +#include <ofono/gprs.h>
> +#include <ofono/gprs-context.h>
> +#include <ofono/sms.h>
> +#include <ofono/ussd.h>
> +#include <ofono/voicecall.h>
> +
> +#include <drivers/atmodem/vendor.h>
> +#include <drivers/atmodem/atutil.h>
> +
> +
> +static const char *none_prefix[] = { NULL };
> +
> +

No double empty lines please.

> +static int telit_probe(struct ofono_modem *modem)
> +{
> +	DBG("");
> +
> +	return 0;
> +}
> +
> +static void telit_remove(struct ofono_modem *modem)
> +{
> +	GAtChat *chat = ofono_modem_get_data(modem);
> +
> +	DBG("");
> +
> +	if (chat) {
> +		g_at_chat_unref(chat);
> +		ofono_modem_set_data(modem, NULL);
> +	}
> +}

Please create a struct telit_data and allocate it in probe. Similar to
what all other drivers do. It is better than just trying to stick the
GAtChat object in the user data.

> +static void cfun_enable_cb(gboolean ok, GAtResult *result, gpointer user_data)
> +{
> +	struct ofono_modem *modem = user_data;
> +
> +	DBG("");
> +
> +	if (ok)
> +		ofono_modem_set_powered(modem, TRUE);
> +}
> +
> +static void cfun_disable_cb(gboolean ok, GAtResult *result, gpointer user_data)
> +{
> +	struct ofono_modem *modem = user_data;
> +	GAtChat *chat = ofono_modem_get_data(modem);
> +
> +	DBG("");
> +
> +	g_at_chat_unref(chat);
> +	ofono_modem_set_data(modem, NULL);

The set_data should only be used on probe() and remove(). Please obey
the lifetime rules of a modem object. They are similar to kernel driver.

> +	if (ok)
> +		ofono_modem_set_powered(modem, FALSE);
> +}
> +
> +static void telit_debug(const char *str, void *user_data)
> +{
> +	const char *prefix = user_data;
> +
> +	ofono_info("%s%s", prefix, str);
> +}
> +
> +static int telit_enable(struct ofono_modem *modem)
> +{
> +	GAtChat *chat;
> +	GIOChannel *channel;
> +	GAtSyntax *syntax;
> +	const char *device;
> +	GHashTable *options;
> +
> +	DBG("%p", modem);
> +
> +	device = ofono_modem_get_string(modem, "Device");
> +	if (device == NULL)
> +		return -EINVAL;
> +
> +	options = g_hash_table_new(g_str_hash, g_str_equal);
> +
> +	if (options == NULL)
> +		return -ENOMEM;
> +
> +	g_hash_table_insert(options, "Baud", "115200");
> +	g_hash_table_insert(options, "Parity", "none");
> +	g_hash_table_insert(options, "StopBits", "1");
> +	g_hash_table_insert(options, "DataBits", "8");

Are these really needed. So far we only needed it for the Calypso modem
which is on a real TTY port. All the other ones were fake TTY ports over
USB or SPI and did not need any extras.

> +
> +	DBG("IN TELIT: %s", device);
> +
> +	channel = g_at_tty_open(device, options);
> +
> +	g_hash_table_destroy(options);
> +
> +	DBG("channel: %p", channel);
> +
> +	if (channel == NULL)
> +		return -EIO;
> +
> +	/*
> +	 * Could not figure out whether it is fully compliant or not, use
> +	 * permissive for now
> +	 * */
> +	syntax = g_at_syntax_new_gsm_permissive();

Use the v1 parser for now. And we see if it is not compliant later.

> +	chat = g_at_chat_new(channel, syntax);
> +	g_io_channel_unref(channel);
> +	g_at_syntax_unref(syntax);
> +
> +	if (chat == NULL)
> +		return -ENOMEM;
> +
> +	if (getenv("OFONO_AT_DEBUG"))
> +		g_at_chat_set_debug(chat, telit_debug, "");
> +
> +	ofono_modem_set_data(modem, chat);

See above comment about struct telit_data and set_data usage.

> +	/* ATE0: disables command echo.
> +	 * +CMEE=1: Enable the Extended Error Result Codes. */
> +	g_at_chat_send(chat, "ATE0+CMEE=1", none_prefix, NULL, NULL, NULL);

Use "ATE0 +CMEE=1" to be a bit more in sync with the other plugins.

> +	/* Set phone functionality:
> +	 * +CFUN=1: mobile full functionality with power saving disabled (factory default).
> +	 * +CFUN=5: mobile full functionality with power saving enabled.
> +	 */
> +	g_at_chat_send(chat, "AT+CFUN=1", none_prefix, cfun_enable_cb, modem, NULL);

If you are supporting online mode, then this is wrong. You need to start
in offline mode. So most likely CFUN=4.

> +
> +	return 0;
> +}
> +
> +static int telit_disable(struct ofono_modem *modem)
> +{
> +	GAtChat *chat = ofono_modem_get_data(modem);
> +
> +	DBG("%p", modem);
> +
> +	if (chat == NULL)
> +		return 0;
> +
> +	/* power down modem */
> +	g_at_chat_cancel_all(chat);
> +	g_at_chat_unregister_all(chat);
> +
> +	g_at_chat_send(chat, "AT+CFUN=0", NULL, cfun_disable_cb, modem, NULL);
> +
> +	return -EINPROGRESS;
> +}
> +
> +static void set_online_cb(gboolean ok, GAtResult *result, gpointer user_data)
> +{
> +	struct cb_data *cbd = user_data;
> +	ofono_modem_online_cb_t cb = cbd->cb;
> +
> +	if (ok)
> +		CALLBACK_WITH_SUCCESS(cb, cbd->data);
> +	else
> +		CALLBACK_WITH_FAILURE(cb, cbd->data);
> +}
> +
> +static void telit_set_online(struct ofono_modem *modem, ofono_bool_t online,
> +				ofono_modem_online_cb_t cb, void *user_data)
> +{
> +	GAtChat *chat = ofono_modem_get_data(modem);
> +	struct cb_data *cbd = cb_data_new(cb, user_data);
> +
> +	char const *command = online ? "AT+CFUN=1" : "AT+CFUN=4";
> +
> +	DBG("modem %p %s", modem, online ? "online" : "offline");
> +
> +	if (chat == NULL)
> +		goto error;
> +
> +	if (g_at_chat_send(chat, command, NULL, set_online_cb, cbd, g_free))
> +		return;
> +
> +error:
> +	g_free(cbd);
> +
> +	CALLBACK_WITH_FAILURE(cb, cbd->data);
> +}
> +
> +
> +
> +static void telit_qss_notify(GAtResult *result, gpointer _sim)
> +{
> +	int status = 0;
> +	GAtResultIter iter;
> +	struct ofono_sim *sim = _sim;
> +	g_at_result_iter_init(&iter, result);
> +
> +	if (!g_at_result_iter_next(&iter, "#QSS:"))
> +		return;
> +
> +	g_at_result_iter_next_number(&iter, &status);
> +	switch(status)
> +	{
> +		case 0:
> +			DBG("SIM not inserted");
> +			ofono_sim_inserted_notify(sim,FALSE);
> +			break;

Please follow the coding style for switch statements here.

> +		case 1:
> +			DBG("SIM inserted");
> +			/* we need to sleep a bit */
> +			sleep(1);
> +			ofono_sim_inserted_notify(sim,TRUE);
> +			break;
> +		case 2:
> +			DBG("SIM inserted and PIN unlocked");
> +			break;
> +		case 3:
> +			DBG("SIM inserted and ready");
> +			break;
> +		default:
> +			return;
> +	}
> +	return;
> +}
> +
> +static void telit_qss_cb(gboolean ok, GAtResult *result, gpointer _sim)
> +{
> +	int mode = 0;
> +	int status = 0;
> +	GAtResultIter iter;
> +	struct ofono_sim *sim = _sim;
> +	g_at_result_iter_init(&iter, result);
> +	
> +	if (!g_at_result_iter_next(&iter, "#QSS:"))
> +		goto error;
> +	g_at_result_iter_next_number(&iter, &mode);
> +	g_at_result_iter_next_number(&iter, &status);
> +	switch(status)
> +	{
> +		case 0:
> +			DBG("SIM not inserted");
> +			break;
> +		case 1:
> +			DBG("SIM inserted");
> +			ofono_sim_inserted_notify(sim,TRUE);
> +			break;
> +		case 2:
> +			DBG("SIM inserted and PIN unlocked");
> +			break;
> +		case 3:
> +			DBG("SIM inserted and ready");
> +			break;
> +		default:
> +			goto error;
> +	} 
> +error:
> +	return;
> +}
> +
> +static void telit_pre_sim(struct ofono_modem *modem)
> +{
> +	GAtChat *chat = ofono_modem_get_data(modem);
> +	struct ofono_sim *sim;
> +
> +	DBG("%p", modem);
> +	DBG("CAHT %p", chat);
> +
> +	ofono_devinfo_create(modem, 0, "atmodem", chat);
> +	sim = ofono_sim_create(modem, OFONO_VENDOR_TELIT, "atmodem", chat);

Why are you using a quirk here?

> +	ofono_voicecall_create(modem, 0, "atmodem", chat);
> +
> +	if(sim) {
> +		/* enable sim state notification */
> +		g_at_chat_send(chat, "AT#QSS=1", NULL, NULL, NULL, NULL);
> +		g_at_chat_register(chat, "#QSS:", telit_qss_notify, FALSE, sim, NULL);
> +		/* query current sim state */
> +		g_at_chat_send(chat, "AT#QSS?", NULL, telit_qss_cb, sim, NULL);

Using NULL for prefix is most likely wrong here. Can you show us some
examples logs with OFONO_AT_DEBUG=1 for this?

> +	}
> +}
> +
> +static void telit_post_sim(struct ofono_modem *modem)
> +{
> +	GAtChat *chat = ofono_modem_get_data(modem);
> +
> +	DBG("%p", modem);
> +
> +	ofono_phonebook_create(modem, 0, "atmodem", chat);
> +}
> +
> +static void telit_post_online(struct ofono_modem *modem)
> +{
> +	GAtChat *chat = ofono_modem_get_data(modem);
> +	struct ofono_message_waiting *mw;
> +	struct ofono_gprs *gprs;
> +	struct ofono_gprs_context *gc;
> +	int gps;
> +
> +	DBG("%p", modem);
> +
> +	gps = ofono_modem_get_integer(modem, "GPS");
> +
> +	if (gps)
> +		g_at_chat_send(chat, "AT$GPSP=1", NULL, NULL, NULL, NULL);

So in general the post_online, pre_sim and post_sim states should only
be used to add atoms and not to send commands.

If you wanna support GPS, then please create a proper atom driver
specific for the Telit modem.

> +
> +	ofono_ussd_create(modem, 0, "atmodem", chat);				// +CUSD - Unstructured Supplementary Service Data

Leave out the comments here.

> +	ofono_call_forwarding_create(modem, 0, "atmodem", chat);
> +	ofono_call_settings_create(modem, 0, "atmodem", chat);
> +	ofono_netreg_create(modem, OFONO_VENDOR_TELIT, "atmodem", chat);
> +	ofono_call_meter_create(modem, 0, "atmodem", chat);
> +	ofono_call_barring_create(modem, 0, "atmodem", chat);
> +	//ofono_cbs_create(modem, 0, "atmodem", chat);				//Cell Broadcast Service

If not used, then leave it out for now.

> +	ofono_sms_create(modem, 0, "atmodem", chat);
> +
> +	gprs = ofono_gprs_create(modem, 0, "atmodem", chat);
> +	gc = ofono_gprs_context_create(modem, 0, "atmodem", chat);
> +
> +	if (gprs && gc)
> +		ofono_gprs_add_context(gprs, gc);
> +
> +	mw = ofono_message_waiting_create(modem);
> +	if (mw)
> +		ofono_message_waiting_register(mw);
> +}
> +
> +static struct ofono_modem_driver telit_driver = {
> +	.name			= "telit",
> +	.probe			= telit_probe,
> +	.remove			= telit_remove,
> +	.enable			= telit_enable,
> +	.disable		= telit_disable,
> +	.set_online		= telit_set_online,
> +	.pre_sim		= telit_pre_sim,
> +	.post_sim		= telit_post_sim,
> +	.post_online	= telit_post_online,
> +};
> +
> +static int telit_init(void)
> +{
> +	return ofono_modem_driver_register(&telit_driver);
> +}
> +
> +static void telit_exit(void)
> +{
> +	ofono_modem_driver_unregister(&telit_driver);
> +}
> +
> +OFONO_PLUGIN_DEFINE(telit, "telit driver", VERSION,
> +		OFONO_PLUGIN_PRIORITY_DEFAULT, telit_init, telit_exit)
> diff --git a/plugins/udev.c b/plugins/udev.c
> index cbb596d..2913b5b 100644
> --- a/plugins/udev.c
> +++ b/plugins/udev.c
> @@ -588,6 +588,44 @@ static void add_linktop(struct ofono_modem *modem,
>  	}
>  }
>  
> +static void add_telit(struct ofono_modem *modem,
> +					struct udev_device *udev_device)
> +{
> +	struct udev_list_entry *entry;
> +	const char *devnode;
> +	gboolean found = FALSE;
> +	gboolean gps = FALSE;
> +
> +	DBG("modem %p", modem);
> +
> +	entry = udev_device_get_properties_list_entry(udev_device);
> +	while (entry) {
> +		const char *name = udev_list_entry_get_name(entry);
> +		const char *value = udev_list_entry_get_value(entry);
> +
> +		if (g_str_equal(name, "OFONO_TELIT_TYPE") == TRUE &&
> +					g_str_equal(value, "modem") == TRUE) {
> +			found = TRUE;
> +		}
> +		if (g_str_equal(name, "OFONO_TELIT_MODEL") == TRUE &&
> +					g_str_equal(value, "UC864-G") == TRUE) {
> +			gps = TRUE;
> +		}
> +		entry = udev_list_entry_get_next(entry);
> +	}
> +
> +	if (found == FALSE)
> +		return;
> +
> +	devnode = udev_device_get_devnode(udev_device);
> +	ofono_modem_set_string(modem, "Device", devnode);
> +
> +	if(gps)
> +		ofono_modem_set_integer(modem, "GPS", 1);
> +
> +	ofono_modem_register(modem);
> +}
> +

Do you happen to have the output of /proc/bus/usb/devices for this
device?

>  static void add_modem(struct udev_device *udev_device)
>  {
>  	struct ofono_modem *modem;
> @@ -682,6 +720,8 @@ done:
>  		add_calypso(modem, udev_device);
>  	else if (g_strcmp0(driver, "tc65") == 0)
>  		add_tc65(modem, udev_device);
> +	else if (g_strcmp0(driver, "telit") == 0)
> +		add_telit(modem, udev_device);
>  	else if (g_strcmp0(driver, "nokiacdma") == 0)
>  		add_nokiacdma(modem, udev_device);
>          else if (g_strcmp0(driver, "linktop") == 0)

Regards

Marcel



  parent reply	other threads:[~2011-05-19 17:48 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-05-19 10:40 [RFC PATCH 1/2] Add basic Telit UC864-G support: Bernhard.Guillon
2011-05-19 10:40 ` [RFC PATCH 2/2] network-registration.c: implement CIND for Telit UC864-G Bernhard.Guillon
2011-05-19 17:51   ` Marcel Holtmann
2011-05-19 17:48 ` Marcel Holtmann [this message]
2011-05-25 13:01   ` [RFC PATCH 1/2] Add basic Telit UC864-G support: Bernhard Guillon
2011-05-25 16:12     ` Marcel Holtmann

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1305827302.15916.200.camel@aeonflux \
    --to=marcel@holtmann.org \
    --cc=ofono@ofono.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.