event-switches.c 13.8 KB
Newer Older
1 2 3 4
/**
 * @file event-switches.c
 * Switch event provider for the Mode Control Entity
 * <p>
Santtu Lakkala's avatar
Santtu Lakkala committed
5
 * Copyright © 2007-2011 Nokia Corporation and/or its subsidiary(-ies).
6
 * Copyright (C) 2014-2019 Jolla Ltd.
7 8
 * <p>
 * @author David Weinehall <david.weinehall@nokia.com>
9 10
 * @author Santtu Lakkala <ext-santtu.1.lakkala@nokia.com>
 * @author Simo Piiroinen <simo.piiroinen@jollamobile.com>
11 12 13 14 15 16 17 18 19 20 21 22 23 24
 *
 * mce is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License
 * version 2.1 as published by the Free Software Foundation.
 *
 * mce 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with mce.  If not, see <http://www.gnu.org/licenses/>.
 */

25
#include "event-switches.h"
26 27

#include "mce.h"
28 29 30 31 32
#include "mce-io.h"

#include <unistd.h>
#include <string.h>
#include <errno.h>
33

34
#include <glib/gstdio.h>
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51

/** ID for the lockkey I/O monitor */
static gconstpointer lockkey_iomon_id = NULL;

/** ID for the keyboard slide I/O monitor */
static gconstpointer kbd_slide_iomon_id = NULL;

/** ID for the cam focus I/O monitor */
static gconstpointer cam_focus_iomon_id = NULL;

/** Can the camera focus interrupt be disabled? */
static gboolean cam_focus_disable_exists = FALSE;

/** ID for the cam launch I/O monitor */
static gconstpointer cam_launch_iomon_id = NULL;

/** ID for the lid cover I/O monitor */
52
static gconstpointer lid_sensor_actual_iomon_id = NULL;
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88

/** ID for the proximity sensor I/O monitor */
static gconstpointer proximity_sensor_iomon_id = NULL;

/** Can the proximity sensor interrupt be disabled? */
static gboolean proximity_sensor_disable_exists = FALSE;

/** ID for the MUSB OMAP3 usb cable I/O monitor */
static gconstpointer musb_omap3_usb_cable_iomon_id = NULL;

/** ID for the mmc0 cover I/O monitor */
static gconstpointer mmc0_cover_iomon_id = NULL;

/** ID for the mmc cover I/O monitor */
static gconstpointer mmc_cover_iomon_id = NULL;

/** ID for the lens cover I/O monitor */
static gconstpointer lens_cover_iomon_id = NULL;

/** ID for the battery cover I/O monitor */
static gconstpointer bat_cover_iomon_id = NULL;

/** Cached call state */
static call_state_t call_state = CALL_STATE_INVALID;

/** Cached alarm UI state */
static alarm_ui_state_t alarm_ui_state = MCE_ALARM_UI_INVALID_INT32;

/** Does the device have a flicker key? */
gboolean has_flicker_key = FALSE;

/**
 * Generic I/O monitor callback that only generates activity
 *
 * @param data Unused
 * @param bytes_read Unused
Santtu Lakkala's avatar
Santtu Lakkala committed
89
 * @return Always returns FALSE to return remaining data (if any)
90
 */
91
static gboolean generic_activity_iomon_cb(mce_io_mon_t *iomon, gpointer data, gsize bytes_read)
92
{
93
	(void)iomon;
94 95 96 97
	(void)data;
	(void)bytes_read;

	/* Generate activity */
98
	mce_datapipe_generate_activity();
Santtu Lakkala's avatar
Santtu Lakkala committed
99 100

	return FALSE;
101 102 103 104 105 106 107
}

/**
 * I/O monitor callback for the camera launch button
 *
 * @param data Unused
 * @param bytes_read Unused
Santtu Lakkala's avatar
Santtu Lakkala committed
108
 * @return Always returns FALSE to return remaining data (if any)
109
 */
110
static gboolean camera_launch_button_iomon_cb(mce_io_mon_t *iomon, gpointer data, gsize bytes_read)
111 112 113
{
	camera_button_state_t camera_button_state;

114
	(void)iomon;
115 116 117 118 119 120 121 122 123 124
	(void)bytes_read;

	if (!strncmp(data, MCE_CAM_LAUNCH_ACTIVE,
		     strlen(MCE_CAM_LAUNCH_ACTIVE))) {
		camera_button_state = CAMERA_BUTTON_LAUNCH;
	} else {
		camera_button_state = CAMERA_BUTTON_UNPRESSED;
	}

	/* Generate activity */
125
	mce_datapipe_generate_activity();
126 127

	/* Update camera button state */
128
	datapipe_exec_full(&camera_button_state_pipe,
129
			   GINT_TO_POINTER(camera_button_state));
Santtu Lakkala's avatar
Santtu Lakkala committed
130 131

	return FALSE;
132 133 134 135 136 137 138
}

/**
 * I/O monitor callback for the lock flicker key
 *
 * @param data The new data
 * @param bytes_read Unused
Santtu Lakkala's avatar
Santtu Lakkala committed
139
 * @return Always returns FALSE to return remaining data (if any)
140
 */
141
static gboolean lockkey_iomon_cb(mce_io_mon_t *iomon, gpointer data, gsize bytes_read)
142
{
143
	key_state_t lockkey_state = KEY_STATE_RELEASED;
144

145
	(void)iomon;
146 147 148 149
	(void)bytes_read;

	if (!strncmp(data, MCE_FLICKER_KEY_ACTIVE,
		     strlen(MCE_FLICKER_KEY_ACTIVE))) {
150
		lockkey_state = KEY_STATE_PRESSED;
151 152
	}

153
	datapipe_exec_full(&lockkey_state_pipe,
154
			   GINT_TO_POINTER(lockkey_state));
Santtu Lakkala's avatar
Santtu Lakkala committed
155 156

	return FALSE;
157 158 159 160 161 162 163
}

/**
 * I/O monitor callback for the keyboard slide
 *
 * @param data The new data
 * @param bytes_read Unused
Santtu Lakkala's avatar
Santtu Lakkala committed
164
 * @return Always returns FALSE to return remaining data (if any)
165
 */
166
static gboolean kbd_slide_iomon_cb(mce_io_mon_t *iomon, gpointer data, gsize bytes_read)
167 168 169
{
	cover_state_t slide_state;

170
	(void)iomon;
171 172 173 174 175 176
	(void)bytes_read;

	if (!strncmp(data, MCE_KBD_SLIDE_OPEN, strlen(MCE_KBD_SLIDE_OPEN))) {
		slide_state = COVER_OPEN;

		/* Generate activity */
177
		mce_datapipe_generate_activity();
178 179 180 181
	} else {
		slide_state = COVER_CLOSED;
	}

182
	datapipe_exec_full(&keyboard_slide_state_pipe,
183
			   GINT_TO_POINTER(slide_state));
Santtu Lakkala's avatar
Santtu Lakkala committed
184 185

	return FALSE;
186 187 188 189 190 191 192
}

/**
 * I/O monitor callback for the lid cover
 *
 * @param data The new data
 * @param bytes_read Unused
Santtu Lakkala's avatar
Santtu Lakkala committed
193
 * @return Always returns FALSE to return remaining data (if any)
194
 */
195
static gboolean lid_sensor_actual_iomon_cb(mce_io_mon_t *iomon, gpointer data, gsize bytes_read)
196
{
197
	cover_state_t lid_state;
198

199
	(void)iomon;
200 201 202
	(void)bytes_read;

	if (!strncmp(data, MCE_LID_COVER_OPEN, strlen(MCE_LID_COVER_OPEN))) {
203
		lid_state = COVER_OPEN;
204 205

		/* Generate activity */
206
		mce_datapipe_generate_activity();
207
	} else {
208
		lid_state = COVER_CLOSED;
209 210
	}

211
	datapipe_exec_full(&lid_sensor_actual_pipe,
212
			   GINT_TO_POINTER(lid_state));
Santtu Lakkala's avatar
Santtu Lakkala committed
213 214

	return FALSE;
215 216 217 218 219 220 221
}

/**
 * I/O monitor callback for the proximity sensor
 *
 * @param data The new data
 * @param bytes_read Unused
Santtu Lakkala's avatar
Santtu Lakkala committed
222
 * @return Always returns FALSE to return remaining data (if any)
223
 */
224
static gboolean proximity_sensor_iomon_cb(mce_io_mon_t *iomon, gpointer data, gsize bytes_read)
225
{
226
	cover_state_t proximity_sensor_actual;
227

228
	(void)iomon;
229 230 231 232
	(void)bytes_read;

	if (!strncmp(data, MCE_PROXIMITY_SENSOR_OPEN,
		     strlen(MCE_PROXIMITY_SENSOR_OPEN))) {
233
		proximity_sensor_actual = COVER_OPEN;
234
	} else {
235
		proximity_sensor_actual = COVER_CLOSED;
236 237
	}

238
	datapipe_exec_full(&proximity_sensor_actual_pipe,
239
			   GINT_TO_POINTER(proximity_sensor_actual));
Santtu Lakkala's avatar
Santtu Lakkala committed
240 241

	return FALSE;
242 243 244 245 246 247 248
}

/**
 * I/O monitor callback for the USB cable
 *
 * @param data The new data
 * @param bytes_read Unused
Santtu Lakkala's avatar
Santtu Lakkala committed
249
 * @return Always returns FALSE to return remaining data (if any)
250
 */
251
static gboolean usb_cable_iomon_cb(mce_io_mon_t *iomon, gpointer data, gsize bytes_read)
252 253 254
{
	usb_cable_state_t cable_state;

255
	(void)iomon;
256 257 258 259 260 261 262 263 264 265
	(void)bytes_read;

	if (!strncmp(data, MCE_MUSB_OMAP3_USB_CABLE_CONNECTED,
		     strlen(MCE_MUSB_OMAP3_USB_CABLE_CONNECTED))) {
		cable_state = USB_CABLE_CONNECTED;
	} else {
		cable_state = USB_CABLE_DISCONNECTED;
	}

	/* Generate activity */
266
	mce_datapipe_generate_activity();
267

268
	datapipe_exec_full(&usb_cable_state_pipe,
269
			   GINT_TO_POINTER(cable_state));
Santtu Lakkala's avatar
Santtu Lakkala committed
270 271

	return FALSE;
272 273 274 275 276 277 278
}

/**
 * I/O monitor callback for the lens cover
 *
 * @param data The new data
 * @param bytes_read Unused
Santtu Lakkala's avatar
Santtu Lakkala committed
279
 * @return Always returns FALSE to return remaining data (if any)
280
 */
281
static gboolean lens_cover_iomon_cb(mce_io_mon_t *iomon, gpointer data, gsize bytes_read)
282 283 284
{
	cover_state_t lens_cover_state;

285
	(void)iomon;
286 287 288 289 290 291
	(void)bytes_read;

	if (!strncmp(data, MCE_LENS_COVER_OPEN, strlen(MCE_LENS_COVER_OPEN))) {
		lens_cover_state = COVER_OPEN;

		/* Generate activity */
292
		mce_datapipe_generate_activity();
293 294 295 296
	} else {
		lens_cover_state = COVER_CLOSED;
	}

297
	datapipe_exec_full(&lens_cover_state_pipe,
298
			   GINT_TO_POINTER(lens_cover_state));
Santtu Lakkala's avatar
Santtu Lakkala committed
299 300

	return FALSE;
301 302 303 304 305 306 307 308
}

/**
 * Update the proximity state
 *
 * @note Only gives reasonable readings when the proximity sensor is enabled
 * @return TRUE on success, FALSE on failure
 */
309
static gboolean update_proximity_sensor(void)
310
{
311
	cover_state_t proximity_sensor_actual;
312 313 314 315 316 317 318 319 320 321
	gboolean status = FALSE;
	gchar *tmp = NULL;

	if (mce_read_string_from_file(MCE_PROXIMITY_SENSOR_STATE_PATH,
				      &tmp) == FALSE) {
		goto EXIT;
	}

	if (!strncmp(tmp, MCE_PROXIMITY_SENSOR_OPEN,
		     strlen(MCE_PROXIMITY_SENSOR_OPEN))) {
322
		proximity_sensor_actual = COVER_OPEN;
323
	} else {
324
		proximity_sensor_actual = COVER_CLOSED;
325 326
	}

327
	datapipe_exec_full(&proximity_sensor_actual_pipe,
328
			   GINT_TO_POINTER(proximity_sensor_actual));
329 330 331 332 333 334 335 336 337 338 339 340

	g_free(tmp);

EXIT:
	return status;
}

/**
 * Update the proximity monitoring
 */
static void update_proximity_monitor(void)
{
Santtu Lakkala's avatar
Santtu Lakkala committed
341 342 343
	if (proximity_sensor_disable_exists == FALSE)
		goto EXIT;

344 345 346 347
	if ((call_state == CALL_STATE_RINGING) ||
	    (call_state == CALL_STATE_ACTIVE) ||
	    (alarm_ui_state == MCE_ALARM_UI_VISIBLE_INT32) ||
	    (alarm_ui_state == MCE_ALARM_UI_RINGING_INT32)) {
Santtu Lakkala's avatar
Santtu Lakkala committed
348
		mce_write_string_to_file(MCE_PROXIMITY_SENSOR_DISABLE_PATH, "0");
349
		update_proximity_sensor();
350
	} else {
Santtu Lakkala's avatar
Santtu Lakkala committed
351
		mce_write_string_to_file(MCE_PROXIMITY_SENSOR_DISABLE_PATH, "1");
352
	}
Santtu Lakkala's avatar
Santtu Lakkala committed
353 354 355

EXIT:
	return;
356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388
}

/**
 * Handle call state change
 *
 * @param data The call state stored in a pointer
 */
static void call_state_trigger(gconstpointer const data)
{
	call_state = GPOINTER_TO_INT(data);

	update_proximity_monitor();
}

/**
 * Handle alarm UI state change
 *
 * @param data The alarm state stored in a pointer
 */
static void alarm_ui_state_trigger(gconstpointer const data)
{
	alarm_ui_state = GPOINTER_TO_INT(data);

	update_proximity_monitor();
}

/**
 * Handle submode change
 *
 * @param data The submode stored in a pointer
 */
static void submode_trigger(gconstpointer data)
{
389
	static submode_t old_submode = MCE_SUBMODE_NORMAL;
390 391 392 393 394
	submode_t submode = GPOINTER_TO_INT(data);

	/* If the tklock is enabled, disable the camera focus interrupts,
	 * since we don't use them anyway
	 */
395 396
	if ((submode & MCE_SUBMODE_TKLOCK) != 0) {
		if ((old_submode & MCE_SUBMODE_TKLOCK) == 0) {
397 398 399 400 401
			if ((cam_focus_disable_exists == TRUE) &&
			    (cam_focus_iomon_id != NULL))
				mce_write_string_to_file(MCE_CAM_FOCUS_DISABLE_PATH, "1");
		}
	} else {
402
		if ((old_submode & MCE_SUBMODE_TKLOCK) != 0) {
403 404 405 406 407 408 409 410
			if (cam_focus_disable_exists == TRUE)
				mce_write_string_to_file(MCE_CAM_FOCUS_DISABLE_PATH, "0");
		}
	}

	old_submode = submode;
}

411 412 413 414 415 416 417
/** List of active io monitors for switches */
static GSList *switch_iomon_list = NULL;

/** I/O monitor delete callback
 *
 * @param iomon io monitor that is about to get deleted
 */
418
static void mce_switches_rem_iomon_cb(mce_io_mon_t *iomon)
419 420 421 422 423 424 425 426 427 428 429
{
	switch_iomon_list = g_slist_remove(switch_iomon_list, iomon);
}

/** Helper for adding io monitor for switch device
 *
 * @param path     device path
 * @param input_cb input handler callback
 *
 * @return io monitor id, or NULL in case of errors
 */
430
static gconstpointer mce_switches_add_iomon(const char *path, mce_io_mon_notify_cb input_cb)
431
{
432 433 434 435 436 437
	mce_io_mon_t *iomon =
		mce_io_mon_register_string(-1, path,
					   MCE_IO_ERROR_POLICY_IGNORE,
					   TRUE,
					   input_cb,
					   mce_switches_rem_iomon_cb);
438 439 440 441 442 443 444 445 446 447 448
	if( iomon )
		switch_iomon_list = g_slist_prepend(switch_iomon_list,
						    (gpointer)iomon);

	return iomon;
}

/** Unregister all active io monitors for switches
 */
static void mce_switches_rem_iomon_all(void)
{
449
	mce_io_mon_unregister_list(switch_iomon_list);
450 451
}

452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494
/** Array of datapipe handlers */
static datapipe_handler_t mce_switches_datapipe_handlers[] =
{
	// input triggers
	{
		.datapipe = &call_state_pipe,
		.input_cb = call_state_trigger,
	},
	{
		.datapipe = &alarm_ui_state_pipe,
		.input_cb = alarm_ui_state_trigger,
	},
	// output triggers
	{
		.datapipe  = &submode_pipe,
		.output_cb = submode_trigger,
	},
	// sentinel
	{
		.datapipe = 0,
	}
};

static datapipe_bindings_t mce_switches_datapipe_bindings =
{
	.module   = "mce_switches",
	.handlers = mce_switches_datapipe_handlers,
};

/** Append triggers/filters to datapipes
 */
static void mce_switches_datapipe_init(void)
{
	mce_datapipe_init_bindings(&mce_switches_datapipe_bindings);
}

/** Remove triggers/filters from datapipes
 */
static void mce_switches_datapipe_quit(void)
{
	mce_datapipe_quit_bindings(&mce_switches_datapipe_bindings);
}

495 496 497 498 499 500 501 502 503 504
/**
 * Init function for the switches component
 *
 * @return TRUE on success, FALSE on failure
 */
gboolean mce_switches_init(void)
{
	gboolean status = FALSE;

	/* Append triggers/filters to datapipes */
505
	mce_switches_datapipe_init();
506 507 508

	/* Register I/O monitors */
	lockkey_iomon_id =
509 510 511
		mce_switches_add_iomon(MCE_FLICKER_KEY_STATE_PATH,
				       lockkey_iomon_cb);

512
	kbd_slide_iomon_id =
513 514 515
		mce_switches_add_iomon(MCE_KBD_SLIDE_STATE_PATH,
				       kbd_slide_iomon_cb);

516
	cam_focus_iomon_id =
517 518 519
		mce_switches_add_iomon(MCE_CAM_FOCUS_STATE_PATH,
				       generic_activity_iomon_cb);

520
	cam_launch_iomon_id =
521 522 523
		mce_switches_add_iomon(MCE_CAM_LAUNCH_STATE_PATH,
				       camera_launch_button_iomon_cb);

524
	lid_sensor_actual_iomon_id =
525
		mce_switches_add_iomon(MCE_LID_COVER_STATE_PATH,
526
				       lid_sensor_actual_iomon_cb);
527

528
	proximity_sensor_iomon_id =
529 530 531
		mce_switches_add_iomon(MCE_PROXIMITY_SENSOR_STATE_PATH,
				       proximity_sensor_iomon_cb);

532
	musb_omap3_usb_cable_iomon_id =
533 534 535
		mce_switches_add_iomon(MCE_MUSB_OMAP3_USB_CABLE_STATE_PATH,
				       usb_cable_iomon_cb);

536
	lens_cover_iomon_id =
537 538 539
		mce_switches_add_iomon(MCE_LENS_COVER_STATE_PATH,
				       lens_cover_iomon_cb);

540
	mmc0_cover_iomon_id =
541 542 543
		mce_switches_add_iomon(MCE_MMC0_COVER_STATE_PATH,
				       generic_activity_iomon_cb);

544
	mmc_cover_iomon_id =
545 546 547
		mce_switches_add_iomon(MCE_MMC_COVER_STATE_PATH,
				       generic_activity_iomon_cb);

548
	bat_cover_iomon_id =
549 550
		mce_switches_add_iomon(MCE_BATTERY_COVER_STATE_PATH,
				       generic_activity_iomon_cb);
551 552 553 554 555 556 557 558 559 560 561 562

	update_proximity_monitor();

	if (lockkey_iomon_id != NULL)
		has_flicker_key = TRUE;

	proximity_sensor_disable_exists =
		(g_access(MCE_PROXIMITY_SENSOR_DISABLE_PATH, W_OK) == 0);

	cam_focus_disable_exists =
		(g_access(MCE_CAM_FOCUS_DISABLE_PATH, W_OK) == 0);

Santtu Lakkala's avatar
Santtu Lakkala committed
563 564
	errno = 0;

565 566 567 568 569 570 571 572 573 574 575
	status = TRUE;

	return status;
}

/**
 * Exit function for the switches component
 */
void mce_switches_exit(void)
{
	/* Remove triggers/filters from datapipes */
576
	mce_switches_datapipe_quit();
577 578

	/* Unregister I/O monitors */
579
	mce_switches_rem_iomon_all();
580 581 582

	return;
}