lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20180312190907.174301-9-dmitry.torokhov@gmail.com>
Date:   Mon, 12 Mar 2018 12:09:01 -0700
From:   Dmitry Torokhov <dmitry.torokhov@...il.com>
To:     linux-input@...r.kernel.org, Benson Leung <bleung@...omium.org>
Cc:     Nick Dyer <nick@...anahar.org>, Olof Johansson <olof@...om.net>,
        linux-kernel@...r.kernel.org
Subject: [PATCH 08/14] platform/chrome: chromeos_laptop - rework i2c peripherals initialization

Instead of having separate setup() functions responsible for instantiating
i2c client for each peripheral, let's generalize the behavior and use
common code for instantiating all i2c peripherals.

Signed-off-by: Dmitry Torokhov <dmitry.torokhov@...il.com>
---
 drivers/platform/chrome/chromeos_laptop.c | 467 +++++++++++-----------
 1 file changed, 235 insertions(+), 232 deletions(-)

diff --git a/drivers/platform/chrome/chromeos_laptop.c b/drivers/platform/chrome/chromeos_laptop.c
index 96e962ff38e87..2a81ae4c15c93 100644
--- a/drivers/platform/chrome/chromeos_laptop.c
+++ b/drivers/platform/chrome/chromeos_laptop.c
@@ -25,10 +25,6 @@
 
 #define MAX_I2C_DEVICE_DEFERRALS	5
 
-static struct i2c_client *als;
-static struct i2c_client *tp;
-static struct i2c_client *ts;
-
 static const char *i2c_adapter_names[] = {
 	"SMBus I801 adapter",
 	"i915 gmbus vga",
@@ -50,12 +46,17 @@ enum i2c_peripheral_state {
 	UNPROBED = 0,
 	PROBED,
 	TIMEDOUT,
+	FAILED,
 };
 
 struct i2c_peripheral {
-	int (*add)(enum i2c_adapter_type type);
+	struct i2c_board_info board_info;
+	unsigned short alt_addr;
+	const char *dmi_name;
 	enum i2c_adapter_type type;
+
 	enum i2c_peripheral_state state;
+	struct i2c_client *client;
 	int tries;
 };
 
@@ -67,59 +68,6 @@ struct chromeos_laptop {
 
 static struct chromeos_laptop *cros_laptop;
 
-static struct i2c_board_info cyapa_device = {
-	I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR),
-	.flags		= I2C_CLIENT_WAKE,
-};
-
-static struct i2c_board_info elantech_device = {
-	I2C_BOARD_INFO("elan_i2c", ELAN_TP_I2C_ADDR),
-	.flags		= I2C_CLIENT_WAKE,
-};
-
-static struct i2c_board_info isl_als_device = {
-	I2C_BOARD_INFO("isl29018", ISL_ALS_I2C_ADDR),
-};
-
-static struct i2c_board_info tsl2583_als_device = {
-	I2C_BOARD_INFO("tsl2583", TAOS_ALS_I2C_ADDR),
-};
-
-static struct i2c_board_info tsl2563_als_device = {
-	I2C_BOARD_INFO("tsl2563", TAOS_ALS_I2C_ADDR),
-};
-
-static int mxt_t19_keys[] = {
-	KEY_RESERVED,
-	KEY_RESERVED,
-	KEY_RESERVED,
-	KEY_RESERVED,
-	KEY_RESERVED,
-	BTN_LEFT
-};
-
-static struct mxt_platform_data atmel_224s_tp_platform_data = {
-	.irqflags		= IRQF_TRIGGER_FALLING,
-	.t19_num_keys		= ARRAY_SIZE(mxt_t19_keys),
-	.t19_keymap		= mxt_t19_keys,
-};
-
-static struct i2c_board_info atmel_224s_tp_device = {
-	I2C_BOARD_INFO("atmel_mxt_tp", ATMEL_TP_I2C_ADDR),
-	.platform_data = &atmel_224s_tp_platform_data,
-	.flags		= I2C_CLIENT_WAKE,
-};
-
-static struct mxt_platform_data atmel_1664s_platform_data = {
-	.irqflags		= IRQF_TRIGGER_FALLING,
-};
-
-static struct i2c_board_info atmel_1664s_device = {
-	I2C_BOARD_INFO("atmel_mxt_ts", ATMEL_TS_I2C_ADDR),
-	.platform_data = &atmel_1664s_platform_data,
-	.flags		= I2C_CLIENT_WAKE,
-};
-
 static int chromeos_laptop_get_irq_from_dmi(const char *dmi_name)
 {
 	const struct dmi_device *dmi_dev;
@@ -140,29 +88,15 @@ static int chromeos_laptop_get_irq_from_dmi(const char *dmi_name)
 	return dev_data->instance;
 }
 
-static struct i2c_client *__add_probed_i2c_device(
-		const char *name,
-		int bus,
-		struct i2c_board_info *info,
-		const unsigned short *alt_addr_list)
+static struct i2c_client *
+chromes_laptop_instantiate_i2c_device(int bus,
+				      struct i2c_board_info *info,
+				      unsigned short alt_addr)
 {
 	struct i2c_adapter *adapter;
 	struct i2c_client *client = NULL;
 	const unsigned short addr_list[] = { info->addr, I2C_CLIENT_END };
 
-	if (bus < 0)
-		return NULL;
-
-	/*
-	 * If a name is specified, look for irq platform information stashed
-	 * in DMI_DEV_TYPE_DEV_ONBOARD by the Chrome OS custom system firmware.
-	 */
-	if (name) {
-		info->irq = chromeos_laptop_get_irq_from_dmi(name);
-		if (info->irq < 0)
-			return NULL;
-	}
-
 	adapter = i2c_get_adapter(bus);
 	if (!adapter) {
 		pr_err("failed to get i2c adapter %d\n", bus);
@@ -175,10 +109,13 @@ static struct i2c_client *__add_probed_i2c_device(
 	 * structure gets assigned primary address.
 	 */
 	client = i2c_new_probed_device(adapter, info, addr_list, NULL);
-	if (!client && alt_addr_list) {
+	if (!client && alt_addr) {
 		struct i2c_board_info dummy_info = {
 			I2C_BOARD_INFO("dummy", info->addr),
 		};
+		const unsigned short alt_addr_list[] = {
+			alt_addr, I2C_CLIENT_END
+		};
 		struct i2c_client *dummy;
 
 		dummy = i2c_new_probed_device(adapter, &dummy_info,
@@ -244,115 +181,53 @@ static int find_i2c_adapter_num(enum i2c_adapter_type type)
 	return adapter->nr;
 }
 
-/*
- * Takes a list of addresses in addrs as such :
- * { addr1, ... , addrn, I2C_CLIENT_END };
- * add_probed_i2c_device will use i2c_new_probed_device
- * and probe for devices at all of the addresses listed.
- * Returns NULL if no devices found.
- * See Documentation/i2c/instantiating-devices for more information.
- */
-static struct i2c_client *add_probed_i2c_device(
-		const char *name,
-		enum i2c_adapter_type type,
-		struct i2c_board_info *info,
-		const unsigned short *addrs)
+static int chromeos_laptop_add_peripheral(struct i2c_peripheral *i2c_dev)
 {
-	return __add_probed_i2c_device(name,
-				       find_i2c_adapter_num(type),
-				       info,
-				       addrs);
-}
+	struct i2c_client *client;
+	int bus;
+	int irq;
 
-/*
- * Probes for a device at a single address, the one provided by
- * info->addr.
- * Returns NULL if no device found.
- */
-static struct i2c_client *add_i2c_device(const char *name,
-						enum i2c_adapter_type type,
-						struct i2c_board_info *info)
-{
-	return __add_probed_i2c_device(name,
-				       find_i2c_adapter_num(type),
-				       info,
-				       NULL);
-}
-
-static int setup_cyapa_tp(enum i2c_adapter_type type)
-{
-	if (tp)
-		return 0;
-
-	/* add cyapa touchpad */
-	tp = add_i2c_device("trackpad", type, &cyapa_device);
-	return (!tp) ? -EAGAIN : 0;
-}
-
-static int setup_atmel_224s_tp(enum i2c_adapter_type type)
-{
-	const unsigned short addr_list[] = { ATMEL_TP_I2C_BL_ADDR,
-					     I2C_CLIENT_END };
-	if (tp)
-		return 0;
-
-	/* add atmel mxt touchpad */
-	tp = add_probed_i2c_device("trackpad", type,
-				   &atmel_224s_tp_device, addr_list);
-	return (!tp) ? -EAGAIN : 0;
-}
-
-static int setup_elantech_tp(enum i2c_adapter_type type)
-{
-	if (tp)
-		return 0;
-
-	/* add elantech touchpad */
-	tp = add_i2c_device("trackpad", type, &elantech_device);
-	return (!tp) ? -EAGAIN : 0;
-}
-
-static int setup_atmel_1664s_ts(enum i2c_adapter_type type)
-{
-	const unsigned short addr_list[] = { ATMEL_TS_I2C_BL_ADDR,
-					     I2C_CLIENT_END };
-	if (ts)
-		return 0;
-
-	/* add atmel mxt touch device */
-	ts = add_probed_i2c_device("touchscreen", type,
-				   &atmel_1664s_device, addr_list);
-	return (!ts) ? -EAGAIN : 0;
-}
-
-static int setup_isl29018_als(enum i2c_adapter_type type)
-{
-	if (als)
-		return 0;
+	/*
+	 * Check that the i2c adapter is present.
+	 * -EPROBE_DEFER if missing as the adapter may appear much
+	 * later.
+	 */
+	bus = find_i2c_adapter_num(i2c_dev->type);
+	if (bus < 0)
+		return bus == -ENODEV ? -EPROBE_DEFER : bus;
 
-	/* add isl29018 light sensor */
-	als = add_i2c_device("lightsensor", type, &isl_als_device);
-	return (!als) ? -EAGAIN : 0;
-}
+	if (i2c_dev->dmi_name) {
+		irq = chromeos_laptop_get_irq_from_dmi(i2c_dev->dmi_name);
+		if (irq < 0) {
+			i2c_dev->state = FAILED;
+			return irq;
+		}
 
-static int setup_tsl2583_als(enum i2c_adapter_type type)
-{
-	if (als)
-		return 0;
+		i2c_dev->board_info.irq = irq;
+	}
 
-	/* add tsl2583 light sensor */
-	als = add_i2c_device(NULL, type, &tsl2583_als_device);
-	return (!als) ? -EAGAIN : 0;
-}
+	client = chromes_laptop_instantiate_i2c_device(bus,
+						       &i2c_dev->board_info,
+						       i2c_dev->alt_addr);
+	if (!client) {
+		/*
+		 * Set -EPROBE_DEFER a limited num of times
+		 * if device is not successfully added.
+		 */
+		if (++i2c_dev->tries < MAX_I2C_DEVICE_DEFERRALS) {
+			return -EPROBE_DEFER;
+		} else {
+			/* Ran out of tries. */
+			pr_notice("ran out of tries for device.\n");
+			i2c_dev->state = TIMEDOUT;
+			return -EIO;
+		}
+	}
 
-static int setup_tsl2563_als(enum i2c_adapter_type type)
-{
-	if (als)
-		return 0;
+	i2c_dev->client = client;
+	i2c_dev->state = PROBED;
 
-	/* add tsl2563 light sensor */
-	als = add_i2c_device(NULL, type, &tsl2563_als_device);
-	return (!als) ? -EAGAIN : 0;
+	return 0;
 }
 
 static int __init chromeos_laptop_dmi_matched(const struct dmi_system_id *id)
@@ -366,47 +241,22 @@ static int __init chromeos_laptop_dmi_matched(const struct dmi_system_id *id)
 
 static int chromeos_laptop_probe(struct platform_device *pdev)
 {
+	struct i2c_peripheral *i2c_dev;
 	int i;
 	int ret = 0;
 
 	for (i = 0; i < MAX_I2C_PERIPHERALS; i++) {
-		struct i2c_peripheral *i2c_dev;
-
 		i2c_dev = &cros_laptop->i2c_peripherals[i];
 
 		/* No more peripherals. */
-		if (i2c_dev->add == NULL)
+		if (!i2c_dev->board_info.addr)
 			break;
 
-		if (i2c_dev->state == TIMEDOUT || i2c_dev->state == PROBED)
+		if (i2c_dev->state != UNPROBED)
 			continue;
 
-		/*
-		 * Check that the i2c adapter is present.
-		 * -EPROBE_DEFER if missing as the adapter may appear much
-		 * later.
-		 */
-		if (find_i2c_adapter_num(i2c_dev->type) == -ENODEV) {
+		if (chromeos_laptop_add_peripheral(i2c_dev) == -EPROBE_DEFER)
 			ret = -EPROBE_DEFER;
-			continue;
-		}
-
-		/* Add the device. */
-		if (i2c_dev->add(i2c_dev->type) == -EAGAIN) {
-			/*
-			 * Set -EPROBE_DEFER a limited num of times
-			 * if device is not successfully added.
-			 */
-			if (++i2c_dev->tries < MAX_I2C_DEVICE_DEFERRALS) {
-				ret = -EPROBE_DEFER;
-			} else {
-				/* Ran out of tries. */
-				pr_notice("ran out of tries for device.\n");
-				i2c_dev->state = TIMEDOUT;
-			}
-		} else {
-			i2c_dev->state = PROBED;
-		}
 	}
 
 	return ret;
@@ -415,91 +265,237 @@ static int chromeos_laptop_probe(struct platform_device *pdev)
 static struct chromeos_laptop samsung_series_5_550 = {
 	.i2c_peripherals = {
 		/* Touchpad. */
-		{ .add = setup_cyapa_tp, I2C_ADAPTER_SMBUS },
+		{
+			.board_info	= {
+				I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR),
+				.flags		= I2C_CLIENT_WAKE,
+			},
+			.dmi_name	= "trackpad",
+			.type		= I2C_ADAPTER_SMBUS,
+		},
 		/* Light Sensor. */
-		{ .add = setup_isl29018_als, I2C_ADAPTER_SMBUS },
+		{
+			.board_info	= {
+				I2C_BOARD_INFO("isl29018", ISL_ALS_I2C_ADDR),
+			},
+			.dmi_name	= "lightsensor",
+			.type		= I2C_ADAPTER_SMBUS,
+		},
 	},
 };
 
 static struct chromeos_laptop samsung_series_5 = {
 	.i2c_peripherals = {
 		/* Light Sensor. */
-		{ .add = setup_tsl2583_als, I2C_ADAPTER_SMBUS },
+		{
+			.board_info	= {
+				I2C_BOARD_INFO("tsl2583", TAOS_ALS_I2C_ADDR),
+			},
+			.type		= I2C_ADAPTER_SMBUS,
+		},
 	},
 };
 
+static struct mxt_platform_data atmel_1664s_platform_data = {
+	.irqflags		= IRQF_TRIGGER_FALLING,
+};
+
+static int chromebook_pixel_tp_keys[] = {
+	KEY_RESERVED,
+	KEY_RESERVED,
+	KEY_RESERVED,
+	KEY_RESERVED,
+	KEY_RESERVED,
+	BTN_LEFT
+};
+
+static struct mxt_platform_data chromebook_pixel_tp_platform_data = {
+	.irqflags		= IRQF_TRIGGER_FALLING,
+	.t19_num_keys		= ARRAY_SIZE(chromebook_pixel_tp_keys),
+	.t19_keymap		= chromebook_pixel_tp_keys,
+};
+
 static struct chromeos_laptop chromebook_pixel = {
 	.i2c_peripherals = {
 		/* Touch Screen. */
-		{ .add = setup_atmel_1664s_ts, I2C_ADAPTER_PANEL },
+		{
+			.board_info	= {
+				I2C_BOARD_INFO("atmel_mxt_ts",
+						ATMEL_TS_I2C_ADDR),
+				.platform_data	= &atmel_1664s_platform_data,
+				.flags		= I2C_CLIENT_WAKE,
+			},
+			.dmi_name	= "touchscreen",
+			.type		= I2C_ADAPTER_PANEL,
+			.alt_addr	= ATMEL_TS_I2C_BL_ADDR,
+		},
 		/* Touchpad. */
-		{ .add = setup_atmel_224s_tp, I2C_ADAPTER_VGADDC },
+		{
+			.board_info	= {
+				I2C_BOARD_INFO("atmel_mxt_tp",
+						ATMEL_TP_I2C_ADDR),
+				.platform_data	=
+					&chromebook_pixel_tp_platform_data,
+				.flags		= I2C_CLIENT_WAKE,
+			},
+			.dmi_name	= "trackpad",
+			.type		= I2C_ADAPTER_VGADDC,
+			.alt_addr	= ATMEL_TP_I2C_BL_ADDR,
+		},
 		/* Light Sensor. */
-		{ .add = setup_isl29018_als, I2C_ADAPTER_PANEL },
+		{
+			.board_info	= {
+				I2C_BOARD_INFO("isl29018", ISL_ALS_I2C_ADDR),
+			},
+			.dmi_name	= "lightsensor",
+			.type		= I2C_ADAPTER_PANEL,
+		},
 	},
 };
 
 static struct chromeos_laptop hp_chromebook_14 = {
 	.i2c_peripherals = {
 		/* Touchpad. */
-		{ .add = setup_cyapa_tp, I2C_ADAPTER_DESIGNWARE_0 },
+		{
+			.board_info	= {
+				I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR),
+				.flags		= I2C_CLIENT_WAKE,
+			},
+			.dmi_name	= "trackpad",
+			.type		= I2C_ADAPTER_DESIGNWARE_0,
+		},
 	},
 };
 
 static struct chromeos_laptop dell_chromebook_11 = {
 	.i2c_peripherals = {
 		/* Touchpad. */
-		{ .add = setup_cyapa_tp, I2C_ADAPTER_DESIGNWARE_0 },
+		{
+			.board_info	= {
+				I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR),
+				.flags		= I2C_CLIENT_WAKE,
+			},
+			.dmi_name	= "trackpad",
+			.type		= I2C_ADAPTER_DESIGNWARE_0,
+		},
 		/* Elan Touchpad option. */
-		{ .add = setup_elantech_tp, I2C_ADAPTER_DESIGNWARE_0 },
+		{
+			.board_info	= {
+				I2C_BOARD_INFO("elan_i2c", ELAN_TP_I2C_ADDR),
+				.flags		= I2C_CLIENT_WAKE,
+			},
+			.dmi_name	= "trackpad",
+			.type		= I2C_ADAPTER_DESIGNWARE_0,
+		},
 	},
 };
 
 static struct chromeos_laptop toshiba_cb35 = {
 	.i2c_peripherals = {
 		/* Touchpad. */
-		{ .add = setup_cyapa_tp, I2C_ADAPTER_DESIGNWARE_0 },
+		{
+			.board_info	= {
+				I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR),
+				.flags		= I2C_CLIENT_WAKE,
+			},
+			.dmi_name	= "trackpad",
+			.type		= I2C_ADAPTER_DESIGNWARE_0,
+		},
 	},
 };
 
 static struct chromeos_laptop acer_c7_chromebook = {
 	.i2c_peripherals = {
 		/* Touchpad. */
-		{ .add = setup_cyapa_tp, I2C_ADAPTER_SMBUS },
+		{
+			.board_info	= {
+				I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR),
+				.flags		= I2C_CLIENT_WAKE,
+			},
+			.dmi_name	= "trackpad",
+			.type		= I2C_ADAPTER_SMBUS,
+		},
 	},
 };
 
 static struct chromeos_laptop acer_ac700 = {
 	.i2c_peripherals = {
 		/* Light Sensor. */
-		{ .add = setup_tsl2563_als, I2C_ADAPTER_SMBUS },
+		{
+			.board_info	= {
+				I2C_BOARD_INFO("tsl2583", TAOS_ALS_I2C_ADDR),
+			},
+			.type		= I2C_ADAPTER_SMBUS,
+		},
 	},
 };
 
 static struct chromeos_laptop acer_c720 = {
 	.i2c_peripherals = {
 		/* Touchscreen. */
-		{ .add = setup_atmel_1664s_ts, I2C_ADAPTER_DESIGNWARE_1 },
+		{
+			.board_info	= {
+				I2C_BOARD_INFO("atmel_mxt_ts",
+						ATMEL_TS_I2C_ADDR),
+				.platform_data	= &atmel_1664s_platform_data,
+				.flags		= I2C_CLIENT_WAKE,
+			},
+			.dmi_name	= "touchscreen",
+			.type		= I2C_ADAPTER_DESIGNWARE_1,
+			.alt_addr	= ATMEL_TS_I2C_BL_ADDR,
+		},
 		/* Touchpad. */
-		{ .add = setup_cyapa_tp, I2C_ADAPTER_DESIGNWARE_0 },
+		{
+			.board_info	= {
+				I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR),
+				.flags		= I2C_CLIENT_WAKE,
+			},
+			.dmi_name	= "trackpad",
+			.type		= I2C_ADAPTER_DESIGNWARE_0,
+		},
 		/* Elan Touchpad option. */
-		{ .add = setup_elantech_tp, I2C_ADAPTER_DESIGNWARE_0 },
+		{
+			.board_info	= {
+				I2C_BOARD_INFO("elan_i2c", ELAN_TP_I2C_ADDR),
+				.flags		= I2C_CLIENT_WAKE,
+			},
+			.dmi_name	= "trackpad",
+			.type		= I2C_ADAPTER_DESIGNWARE_0,
+		},
 		/* Light Sensor. */
-		{ .add = setup_isl29018_als, I2C_ADAPTER_DESIGNWARE_1 },
+		{
+			.board_info	= {
+				I2C_BOARD_INFO("isl29018", ISL_ALS_I2C_ADDR),
+			},
+			.dmi_name	= "lightsensor",
+			.type		= I2C_ADAPTER_DESIGNWARE_1,
+		},
 	},
 };
 
 static struct chromeos_laptop hp_pavilion_14_chromebook = {
 	.i2c_peripherals = {
 		/* Touchpad. */
-		{ .add = setup_cyapa_tp, I2C_ADAPTER_SMBUS },
+		{
+			.board_info	= {
+				I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR),
+				.flags		= I2C_CLIENT_WAKE,
+			},
+			.dmi_name	= "trackpad",
+			.type		= I2C_ADAPTER_SMBUS,
+		},
 	},
 };
 
 static struct chromeos_laptop cr48 = {
 	.i2c_peripherals = {
 		/* Light Sensor. */
-		{ .add = setup_tsl2563_als, I2C_ADAPTER_SMBUS },
+		{
+			.board_info	= {
+				I2C_BOARD_INFO("tsl2563", TAOS_ALS_I2C_ADDR),
+			},
+			.type		= I2C_ADAPTER_SMBUS,
+		},
 	},
 };
 
@@ -637,15 +633,22 @@ static int __init chromeos_laptop_init(void)
 
 static void __exit chromeos_laptop_exit(void)
 {
-	if (als)
-		i2c_unregister_device(als);
-	if (tp)
-		i2c_unregister_device(tp);
-	if (ts)
-		i2c_unregister_device(ts);
+	struct i2c_peripheral *i2c_dev;
+	int i;
 
 	platform_device_unregister(cros_platform_device);
 	platform_driver_unregister(&cros_platform_driver);
+
+	for (i = 0; i < MAX_I2C_PERIPHERALS; i++) {
+		i2c_dev = &cros_laptop->i2c_peripherals[i];
+
+		/* No more peripherals */
+		if (!i2c_dev->board_info.type)
+			break;
+
+		if (i2c_dev->state == PROBED)
+			i2c_unregister_device(i2c_dev->client);
+	}
 }
 
 module_init(chromeos_laptop_init);
-- 
2.16.2.660.g709887971b-goog

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ