summaryrefslogtreecommitdiff
path: root/drivers/platform/chrome/chromeos_acpi.c
blob: e6e6dcfc74d1d1bc3fb438ae0cb9593b9f86332f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
// SPDX-License-Identifier: GPL-2.0-only
/*
 * ChromeOS specific ACPI extensions
 *
 * Copyright 2022 Google LLC
 *
 * This driver attaches to the ChromeOS ACPI device and then exports the
 * values reported by the ACPI in a sysfs directory. All values are
 * presented in the string form (numbers as decimal values) and can be
 * accessed as the contents of the appropriate read only files in the
 * sysfs directory tree.
 */
#include <linux/acpi.h>
#include <linux/platform_device.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/module.h>

#define ACPI_ATTR_NAME_LEN 4

#define DEV_ATTR(_var, _name)					\
	static struct device_attribute dev_attr_##_var =	\
		__ATTR(_name, 0444, chromeos_first_level_attr_show, NULL);

#define GPIO_ATTR_GROUP(_group, _name, _num)						\
	static umode_t attr_is_visible_gpio_##_num(struct kobject *kobj,		\
						   struct attribute *attr, int n)	\
	{										\
		if (_num < chromeos_acpi_gpio_groups)					\
			return attr->mode;						\
		return 0;								\
	}										\
	static ssize_t chromeos_attr_show_gpio_##_num(struct device *dev,		\
						      struct device_attribute *attr,	\
						      char *buf)			\
	{										\
		char name[ACPI_ATTR_NAME_LEN + 1];					\
		int ret, num;								\
											\
		ret = parse_attr_name(attr->attr.name, name, &num);			\
		if (ret)								\
			return ret;							\
		return chromeos_acpi_evaluate_method(dev, _num, num, name, buf);	\
	}										\
	static struct device_attribute dev_attr_0_##_group =				\
		__ATTR(GPIO.0, 0444, chromeos_attr_show_gpio_##_num, NULL);		\
	static struct device_attribute dev_attr_1_##_group =				\
		__ATTR(GPIO.1, 0444, chromeos_attr_show_gpio_##_num, NULL);		\
	static struct device_attribute dev_attr_2_##_group =				\
		__ATTR(GPIO.2, 0444, chromeos_attr_show_gpio_##_num, NULL);		\
	static struct device_attribute dev_attr_3_##_group =				\
		__ATTR(GPIO.3, 0444, chromeos_attr_show_gpio_##_num, NULL);		\
											\
	static struct attribute *attrs_##_group[] = {					\
		&dev_attr_0_##_group.attr,						\
		&dev_attr_1_##_group.attr,						\
		&dev_attr_2_##_group.attr,						\
		&dev_attr_3_##_group.attr,						\
		NULL									\
	};										\
	static const struct attribute_group attr_group_##_group = {			\
		.name = _name,								\
		.is_visible = attr_is_visible_gpio_##_num,				\
		.attrs = attrs_##_group,						\
	};

static unsigned int chromeos_acpi_gpio_groups;

/* Parse the ACPI package and return the data related to that attribute */
static int chromeos_acpi_handle_package(struct device *dev, union acpi_object *obj,
					int pkg_num, int sub_pkg_num, char *name, char *buf)
{
	union acpi_object *element = obj->package.elements;

	if (pkg_num >= obj->package.count)
		return -EINVAL;
	element += pkg_num;

	if (element->type == ACPI_TYPE_PACKAGE) {
		if (sub_pkg_num >= element->package.count)
			return -EINVAL;
		/* select sub element inside this package */
		element = element->package.elements;
		element += sub_pkg_num;
	}

	switch (element->type) {
	case ACPI_TYPE_INTEGER:
		return sysfs_emit(buf, "%d\n", (int)element->integer.value);
	case ACPI_TYPE_STRING:
		return sysfs_emit(buf, "%s\n", element->string.pointer);
	case ACPI_TYPE_BUFFER:
		{
			int i, r, at, room_left;
			const int byte_per_line = 16;

			at = 0;
			room_left = PAGE_SIZE - 1;
			for (i = 0; i < element->buffer.length && room_left; i += byte_per_line) {
				r = hex_dump_to_buffer(element->buffer.pointer + i,
						       element->buffer.length - i,
						       byte_per_line, 1, buf + at, room_left,
						       false);
				if (r > room_left)
					goto truncating;
				at += r;
				room_left -= r;

				r = sysfs_emit_at(buf, at, "\n");
				if (!r)
					goto truncating;
				at += r;
				room_left -= r;
			}

			buf[at] = 0;
			return at;
truncating:
			dev_info_once(dev, "truncating sysfs content for %s\n", name);
			sysfs_emit_at(buf, PAGE_SIZE - 4, "..\n");
			return PAGE_SIZE - 1;
		}
	default:
		dev_err(dev, "element type %d not supported\n", element->type);
		return -EINVAL;
	}
}

static int chromeos_acpi_evaluate_method(struct device *dev, int pkg_num, int sub_pkg_num,
					 char *name, char *buf)
{
	struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
	acpi_status status;
	int ret = -EINVAL;

	status = acpi_evaluate_object(ACPI_HANDLE(dev), name, NULL, &output);
	if (ACPI_FAILURE(status)) {
		dev_err(dev, "failed to retrieve %s. %s\n", name, acpi_format_exception(status));
		return ret;
	}

	if (((union acpi_object *)output.pointer)->type == ACPI_TYPE_PACKAGE)
		ret = chromeos_acpi_handle_package(dev, output.pointer, pkg_num, sub_pkg_num,
						   name, buf);

	kfree(output.pointer);
	return ret;
}

static int parse_attr_name(const char *name, char *attr_name, int *attr_num)
{
	int ret;

	ret = strscpy(attr_name, name, ACPI_ATTR_NAME_LEN + 1);
	if (ret == -E2BIG)
		return kstrtoint(&name[ACPI_ATTR_NAME_LEN + 1], 0, attr_num);
	return 0;
}

static ssize_t chromeos_first_level_attr_show(struct device *dev, struct device_attribute *attr,
					      char *buf)
{
	char attr_name[ACPI_ATTR_NAME_LEN + 1];
	int ret, attr_num = 0;

	ret = parse_attr_name(attr->attr.name, attr_name, &attr_num);
	if (ret)
		return ret;
	return chromeos_acpi_evaluate_method(dev, attr_num, 0, attr_name, buf);
}

static unsigned int get_gpio_pkg_num(struct device *dev)
{
	struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
	union acpi_object *obj;
	acpi_status status;
	unsigned int count = 0;
	char *name = "GPIO";

	status = acpi_evaluate_object(ACPI_HANDLE(dev), name, NULL, &output);
	if (ACPI_FAILURE(status)) {
		dev_err(dev, "failed to retrieve %s. %s\n", name, acpi_format_exception(status));
		return count;
	}

	obj = output.pointer;

	if (obj->type == ACPI_TYPE_PACKAGE)
		count = obj->package.count;

	kfree(output.pointer);
	return count;
}

DEV_ATTR(binf2, BINF.2)
DEV_ATTR(binf3, BINF.3)
DEV_ATTR(chsw, CHSW)
DEV_ATTR(fmap, FMAP)
DEV_ATTR(frid, FRID)
DEV_ATTR(fwid, FWID)
DEV_ATTR(hwid, HWID)
DEV_ATTR(meck, MECK)
DEV_ATTR(vbnv0, VBNV.0)
DEV_ATTR(vbnv1, VBNV.1)
DEV_ATTR(vdat, VDAT)

static struct attribute *first_level_attrs[] = {
	&dev_attr_binf2.attr,
	&dev_attr_binf3.attr,
	&dev_attr_chsw.attr,
	&dev_attr_fmap.attr,
	&dev_attr_frid.attr,
	&dev_attr_fwid.attr,
	&dev_attr_hwid.attr,
	&dev_attr_meck.attr,
	&dev_attr_vbnv0.attr,
	&dev_attr_vbnv1.attr,
	&dev_attr_vdat.attr,
	NULL
};

static const struct attribute_group first_level_attr_group = {
	.attrs = first_level_attrs,
};

/*
 * Every platform can have a different number of GPIO attribute groups.
 * Define upper limit groups. At run time, the platform decides to show
 * the present number of groups only, others are hidden.
 */
GPIO_ATTR_GROUP(gpio0, "GPIO.0", 0)
GPIO_ATTR_GROUP(gpio1, "GPIO.1", 1)
GPIO_ATTR_GROUP(gpio2, "GPIO.2", 2)
GPIO_ATTR_GROUP(gpio3, "GPIO.3", 3)
GPIO_ATTR_GROUP(gpio4, "GPIO.4", 4)
GPIO_ATTR_GROUP(gpio5, "GPIO.5", 5)
GPIO_ATTR_GROUP(gpio6, "GPIO.6", 6)
GPIO_ATTR_GROUP(gpio7, "GPIO.7", 7)

static const struct attribute_group *chromeos_acpi_all_groups[] = {
	&first_level_attr_group,
	&attr_group_gpio0,
	&attr_group_gpio1,
	&attr_group_gpio2,
	&attr_group_gpio3,
	&attr_group_gpio4,
	&attr_group_gpio5,
	&attr_group_gpio6,
	&attr_group_gpio7,
	NULL
};

static int chromeos_acpi_device_probe(struct platform_device *pdev)
{
	chromeos_acpi_gpio_groups = get_gpio_pkg_num(&pdev->dev);

	/*
	 * If the platform has more GPIO attribute groups than the number of
	 * groups this driver supports, give out a warning message.
	 */
	if (chromeos_acpi_gpio_groups > ARRAY_SIZE(chromeos_acpi_all_groups) - 2)
		dev_warn(&pdev->dev, "Only %zu GPIO attr groups supported by the driver out of total %u.\n",
			 ARRAY_SIZE(chromeos_acpi_all_groups) - 2, chromeos_acpi_gpio_groups);
	return 0;
}

static const struct acpi_device_id chromeos_device_ids[] = {
	{ "GGL0001", 0 },
	{ "GOOG0016", 0 },
	{}
};
MODULE_DEVICE_TABLE(acpi, chromeos_device_ids);

static struct platform_driver chromeos_acpi_device_driver = {
	.probe = chromeos_acpi_device_probe,
	.driver = {
		.name = KBUILD_MODNAME,
		.dev_groups = chromeos_acpi_all_groups,
		.acpi_match_table = chromeos_device_ids,
	}
};
module_platform_driver(chromeos_acpi_device_driver);

MODULE_AUTHOR("Muhammad Usama Anjum <usama.anjum@collabora.com>");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("ChromeOS specific ACPI extensions");
uIq3R<`:% T8R5^4w$k3!S551U&Ρ^zbO6wIV kw1$ Y niz@1-R/٭ U6F&rcqk SΨ=In1rbqeՊU,M܀dlHiJaHtKѮ^~uIwU gÅy|2^żLB?x:(qY*z{Xe @ kDE׊9o. mH)lX<6r֖_q$oI#dj~cs*/WeŜ~~WIj:}@ez2fP>%2,mA&m# \ZI2 ȹ7ZS\IаU`Ǔyud3z.dM+esOL4^? yę"$`Xx+P!:Uta6х|<6il1$ʀǖ,l+ Y<> ]:bՑhHu0OP(uKϡI~7ߩE0._rp2(da}\';A?J.+h=+Fɗ ̄GLk/E$P i&'~ "# 6Fy$>j1) CYHJR$C1b".sنWB\p#Jy"(2ڙ0_n}4oTgv*7É65;=Pxg: 9&Eӷ0Pn['e.dP&KejD HU< 2;rXDĕ) u*t8PY2D> 0ҷ:85.R^8}g$hlIdw0ȐMI/>N`Bt|z(^gIvk[[BG=a+\W+pqekomt Vj+McR8?[ Nd1`9˶{Rma2& |:ï߰^.Γ~#o~347 `诸pY-QH0Q$ OPOjg dA#Vq08GZ[cG S h016QM?@I덐R`4tkǴ̑ + ^|W5N L4E? ?CعX-vI 2[ϛ>,v_^L+l55ї=cz{heu^N5›^iVOEG`Co{&5IH:% _YRB;<QV"B@'`(}T f| =|w.ӁYslX7?[`ܑ¨M-f Oo`/@d% F:^\k}&Ri -2Ӆ&XOq/ vw<` jtyT=\Fd<9+tYu3^ 7¥6~k%XfT']a¤$Ͱ*ф_ofKu~KDB֊Y2.5A@Rr_րjg<}*3A$ c-J:S(x!dheHA|-TCi LSދ c;+ ?WMOLH3[WΤ%8;pp@kJKk_Ɔ|RQnAXND;Y(l5h^$,geQ*P\-I،ԑ9f*ki9kqTBD-/f.HXኤD\aq&ڀ0{, 8 f p \8]7$sO*p8QspR^~fX/K1*yjiwGj0U=0[7R80œh) fB/5Y̕Hd9= M?9( %"gyB+oeGEzj&-1\l8EG}T!f䪺Ia{e9nङYN< ;Q, Kk5Ȍ]΂΢lGrNq%ђmpqb v;z7fËP]iG}U\Ju&}_66 +L}#N" # |Nɟ5hҲ"4qPL%?j;0왳QcjF]XiMZjS=(:TrG3L<4G/4^vIlĒ4tDŽ\'\թn=;k&k#K%?:9Z-}p?e|zH3%JIֲF.[pkŰjϧy {xr7GiFtKx#mi*37~ 2 vn@J$or"G{ڣ"&{ i͔'Wcwu$ D?>N 8Ţb*sii-ZT4,J\ ԵRcX,3A̳zW-Me߁B鞫ŽZV6,_קeӼ qxr1>4]vd9K2< _YOT: jp8hjz+#L2u@F%Pمz_fٗ I? w%Xz؂& q_3^'PDDI] 5Zn]8>*q~bViC$Bԯe/cWֹY'B!`2%UR=p[2iUájVC.=K!FD_7w BAXy{?a |[{'1h#,EhG[:UXFS=Q;nk똩UC/+&Rci7OK$&-lfRZ] ^܍r$M*2$I*J1bzNE<psR,B\Z;C<>BI0ٮWIc@ݥEsg_naKa,&"KӷQ hݺk+NY?0@PF]t{2oy,W7oVKe= ZWպğ6F9B;쒸qzo<(7~nVQF~Z0]X/ui3MU9f)1 }vlzpP|f[K@`N}f[8-mƯvZݣD5i "~&8ЅHTxH]tR~ȧE:~ɽA̸ex!wGIw;SMr̈́|!aj] |dXDKCi@fS=5l?Z,л2yl1T I䗩jF[G[ۗIƌ\61M`_SlaWke!,[gn}&m[ uLډQcTqlE!ZfU,$7=aI4M5xB AaDJ|B[ߟl'9 htU}ңEK;T5 ʬ~_b: xϜVq[y3538S80-PpVjd0M5:wS4Xݣ} X;v}F0+S<>Na 1Ҽ Ƃc3P[.F-wyNIK/GM7le}Ӹ5t۩)W(N} D†UJ>:L(O ;: eh^^ރD)>{_$jF^IbiMtH"NtK#PdԎ?aB 6UK7˅\}Q:ez 4JVJne'wN0=FOBl65wirWlJwvc"VNɕ=ړUBU 2^&dD0hH&2KSČKhq13..HC~XTaC(YMϕ< oHbe+ }7# ?XP2ȭ}Ay)x[Y_+Vl0d2<Ćb"fg f dZ_Zf%t`3Z  6YCy%5D`&o-s'Ko;Yj}\[(I2Zw_8Ȭɬ7 Dzzz`%۫7OdYX5D5;]B1Y5"}}zGF4 g3tszG4+J%tk6YSzh:xtp~Jbe?ru;ry?x@SݴZNiIH0M J-,m JXy)19vwn(KYU^f:t볮O2+R'. S(Voh 2RRfl_Q_{F167 E⯲~n8 p \z <#גtWBb U2vM*Uc* ҫĕ.FN?NNwhT`阄i[NyU-Hz8d5ҺVfR//uLGM#N ~L8t1{ŕ8l33:{D 21TK+7JZG֧;x@kq#ŒSƽ pf7}T!5FIXcXjڇG }5jUM%}KZۨw[!WV> KqÛf<~*5]uep$#m"PvQpF&nxI%rJq2 :UB.['QfJV+>sWr|ew73<[@뤪>or[ 8)X1iAJ$KwaڇjD ԁFKY6̙ycfW g"jPՕОި:rotU 2݅Ũwr[l"l{Iа%bk2sG͘Ӟ&ThQUl+NfNcDv\Y)UNh֛͒ܿ9m0~fBBC%VD>.qY[rV/ToS r\5/jYF5oUQ^Oh\_;]DihS29CU2!ۜK<51@aZ2 ՚)N9R c.y\G'HR5$$QV!S5SJTKU.I/enP_4D"/&BSSVf&[L֒:^*?A\#H!7-d].0]PӢk٨aHaL"]¨|CNˢhy&2KޙAUs.Pqya&Ѱd}~153 'ޭ_sdxf4ԃw&B+a"Q2'eXh!wIxiFꕯ9ǝ͏7![p# ԂK 0Q{5y=m?akU2\QJx7NBr)ͥl.-J͌CSx_j,j񕖇"YLݖtu0FG{:n-(fv:?L!0b? EsCb0êGj\{nna)z59rjEfAM!.yu@5j)Xt_N]jaO f4<]ڃ%/dXtztU)aaܥ)Qa3ZY7lίs==u@E $HV9#낣Do_$>rBu ,/J ԰_qV 1<6mb_QWɒ^A[b3%LHGZtC.lLhw&eޢS8S*u[lȏ[9ϱj;6N,˚V@(J: 3ĀDoTs]_H?~}t+à. 7*)?u7f]'l4Ԇ-7NR;.hMYL_HD P9ȉ49IeE]u9Mt&8 'S4c(4'T*: Tm`/#&o@F@l V, 8i5$|:E3D`m,)HsD6f_Of}`ßF#PZ4?)* HzRZXY.qN:ObqzAg33(""+R>Pv_+Y'@trռ3jd 6}MF?  v``o4 ЪgYZDݝCOY:ِ`v>uX\C={ xRׂt=Wa][6< +CpH&dIY'槏jKu t .tRD=e~vAin0=PIoͧo|bZ!p£,QSupb # ڑyR g4bQ3~6Fi4mn~ͱTv9aYՁEE3TS*u/.n+jo ukUw$ҺIM`֝%itgԅ pw߭I)gE}F|4Wփl2[`}vsj7;dC5+TOIE!1fC5FcV;~=/SD?, ەdib$3Jq\5MZ2"yLO\@\b2&8$XU6[V,, y Nd|9dB,b#'u ߃ps[+3h-Nn9+2d1P86h)CU;>r.XKJv-쬬Qh倷xȪ$_XzpZhq㜴45b{{r %`Ũ5 {+fi9?9ZBꉿʟoP <ZK@ r m],OԮW֕wr#vtn |+|i~r7n \&k3$RNzCJ;=Q4BtaB]Cr] @9E[-a {$p%x#FjcG/ժoo޼j[`^\ݑlZFu |VexC`+GzBkĖLCDzhptFAEsn.Pa;v8<:QФLЙ5 ?Y?D͞LoL "fxn] Ae1B3 .||H)W'?Z/F/]c4%v|ws2|qws 37N<-@YM3-4)af5dAvigm@4 U{z_^Y6p@Sxܝ G4|~ Ґ|QK{W|u;+ߧrZ-puɃ2IH.3xo _=dyƽe5(P' yD4]y CSNigHFOB js8 %K3p#i0FLXb)Һpu'M5kAcՠl : 0SLoKدzv#/l;%H~1 I~4Ne ?%0R '^NWY;2Co+${0Y[sY.yݱb8WH&k}l3J*R1*e05tj`y*1yr$@")}R Y֮K^̕*tpv .dM duQy%Vv._^/qCM?JܹnsP,Z|`i]13wcdLlYRQgwKH&CHXT/,"7<+EO^R=Z2%0O䂅轵z Y멿EʵJ7 p@#Z/SLQ|9rΚV/R4j*iAu!a=ƎUQK?aH2Ny5LJc''=;<9(|eN+(RY:XnkM?Q_k Һp44o '}s9q#)-a1<$xX0X2.Dn>?_ˇ*pCZكEaĹ GE7EvIR瞊Ȍ+y0KG HMY+#f$㈨3V0 ?g1*)c^ H"fmuƔ+Q7[nHr# :h 2Aiͅ4mF2T5Ό v9#[ uw7jH7ᄊ]Lxa;t R|߈'8/i+-VQr էޢwq$o I kZ7VI E"2%~*rɺbT]?曆k;&8yr2)|\dZ|M"eVY0iN Zv3XmM,? )߹,!ѹq ӊE@&/S=|Q<嗣kb]Wξ 'ÓKP:pm\q.Si W&%ZϯYC`=5JuW2on Ӽ&~6j@nfAɫ[4R'!zzw=E6D>'RnF_MOȢ(n1t* V.z4nwëV$5Tz^g0_%| _ +˛`ﮍج,ePU64y=[mb )-fV]QPZjL<0N>E; zk+o@/KפF~gS݌ ࣆ@u͌@LWkfBF2;$hk`?7Kr5-Ć_LEߔ)?uxVz=H'#С%5.pOdhĹ9Ӏ-1n׿|x^@.4<^w9Q: -zmް>/30锞]9n{Y yNA||F/M:6 hQ+)NLϗcpkfF+xkoᣱ^ Ps 'W7IAZLs 8zRhxR++I:n-Z֙>$g`cw3D{ ȋkVtnVј)<$t֙O'Kا/_]JA15$#Yj6gDx0jv*O%< CX`-tJ:Џ^~b9+,wCs DʰJ즧zrugeԹA\"[uqۧ]KZ QxTQ8|6a0 iDJYn/Ҕ:O9feO:2^d5enȰ?~>Kˋ+A)'VA@n VO:widhQfJIb'U.o09Д2+d䢾HeWjG!@2(;a>Yv:rGmKV^S(+x j? Q7H夽G ,Ӝ $ʰ B|72Or+Aꅊ-l}Maũ` 8PhJ ,$ieD0e6/&d|Q̖u J(gcV}"%&^+UmK;zỻO+ K3V,jLGę/[rnFEf5 9MO*lۑ8EiES k$oIWuI/cH-F,ߥ~MNi_hy6di fdW~rsG]KZ{= f3s65QϜJfquPIp΀1Xg{-&q=j4H6NCuZ]SM}$L?I }qs: }+걳rH3dudiq+u:XQ֏݆.OCώ_ Ÿo'd"-;,+R$fNGUfY,;2TgS봂X.*ʮ-)`E`&$#4 mФ/z攊"= 7jiU\Ɯ# ɤj}W4isaWWҺdY=Z"]oi I~pd6;5vU:xҢaךqT5ꍻj\i+.:y \ubgю,(b7JV٬km\[WRnPmpdoº kvVJHM xP$KRhn`^Q0} Юn@$ewBꚅX(^$Tg`ab }t1EuS*f b9̉\jtu.f_ 7w+zF% A,A =G9e׿/;71`\[?#DOt:=ϓ|VES\7v^ZK[ 350e][86]3v \ b'4@jj%{_Jhlv{^LwY<*JbR@:ȯw\;=kPq<4z,%V."+cf̰Ap-lF)Kֵ49@m 6FY*N=VŨX;~59%J톄_e`Lq{S޵]B]~H`_~'k 銟IR[\LUH;uK.rR)TAӤˋo`~IH9qӟ S/Ɏ eE%9ڤ0.:ntZ D[]01=X ޶;XuiKHbcuW)P-xn,$6f=FL;VpQQ] GSQgMsp%lW]o7QY9L.3Gq928S.{mc iMGvG+;[ Ne7#ڷ uƒ yffr]fO$_|L}N?llTwB{6CfAcD7*XdA;- KTuHgWry2| 1x,ئם Fc{|kXlpf9TwߓEtlQRiWP.MMܑ8Fyɫ_ @߷8aƁSt3Þ/N$'qN .X65Y{Vu;^n iq)Z^`rct4xlpabG)=-Rnx!EG#ouX KIhӍ=R^N6dOfuSMdO#ihL[pTeը3V@p 7ltqEh7xz ‚ђk'ԥ?%ϱr%^^шC@[E\uO E Ӂ֌ &GŒƹ5;) 4/,7U֔q~ʊs]ORoꅓD@ :z̞PcIH.TfCVFj[[g~5u&j;.rG@KHg2n96+%@cx f#%VƐrM.e/[w.V4;1t*oWsqh(mA4t*?uMBzgps=SܩZC%۠Pms>ԶHB| fOPjR#F KQf=&o/ZLaVK } R8`$Jfn4+g@Z)`iDs6$\Z&ATCA[IYNJZ> /=4H:t neWGo%4iiږN/d:ɲC%zr:8;%lN\v V"n~$4f\5 {jX@ܯ@1ӌˮ z&$x|WWr abf%Q?pENwZPk]h阱lu%1\&lXq,UkEnG5|jb2xn9.!"Z>MP~<-BӍ%Fޡ YD3]PbeRUKոݣBl!J7옭)>ix:rNR?_eI ѧ=aߨ6i9a,26*zr #իX9TfyvykDLhpgfab$-)@+p64_X;x_ K.@KB#Tc'܆$=|rp!M9i-)r6OMZv6{=[%/UӣFHcBSl1c?_I- =f~˱kdG۞76@Koa-hL|IƟM炭'G}e-[L$4#sϛݓ!JQH z9S*0>@ Kv. $? iVX&ը fE{tF|Mۃ]DH'-@ʝ9r#A\,pdrw- 5]Uw EFOJ%A-LdyU $!ofv!`m,TuA)gR=ty57AE:D1F)A9(BҌG Jy_lΆ!:2> 26AN 膡clBcpD,!VAtZ ,AwRW?[aUmVܜr^ik=)uZd%boӂTTê}w*kO> ursV2'!j~%Vp>E<DկOawU%E!f%>iNjNg<tҝ6T?(՟d`vfP$mAq\MIo}FImFiqJSO``G)/GF#N6(] [rԊqorv]5'/oOObV- i É|pp*^BpJ6Y0,_w"b=;bIcAS=} SBP@[B02JN<[D iD5xJ ,F#$Oh$:긛k)BdHҍ<=ߢe_6jm_̧:֞GFbҀbqoж(SⶰiPA t2eSJ.R2V(:T<sb|#vmE^L7Vc %NJc.c#_f\?ղL+7E^JfKgS?D㣄fvwgEpL^n [簶84'ITjRf ) PH5#:l)!FkbNb ǥQVoP6[x"/އ" mTΪT{'wcL5 ?ۋ ȧnk07eyLb`3/᩹ufFΈ !IsMZ;8d޹Ob|ݳ/ġFgG$֩7&^{v2B L~9VB>6j*Oܸt8~> 'C5/rͷvxysv&ynt?K/=lGk"g _xJΊ!{5?"VL XQ\W[$T.x__FnueX*v2Z.R˝bc={}gyH9KEWDAe9Q%!݂f1òE Xi5+9iXz m-x*o\G2 7#g}8ȃyMt*&TjpkCM\~I} |Zڍ^)#o)4wh=\>a;ZĮd\3!{Rj]A%fQm)l`rʹb o`KïP\vf{&*n9}}Nmk(_e^ { hh Zn,!`P^L a r,'L VT|EQRW]bq=V}s_|Sɲr{o>so_#ȱk,k(ڏ]R[˳ߟ ^m)ΤJv|rx6s#Z|::ffGէH'4.I:kJ>Pr0ie3WG_+ kC GYGCA=Q ,lDgD!Af\p~*܊5x@Ԭg6' 'n<)xIo6F ׆Y#x5NkհA-oyUmJ{MYܨz)wʑ@fsE o8#|-Mo1Z?Y#\+$?W]7g޹ bv)#vHZ&*r,YnW7W9i^+*zVɮ4X+xBt{yuCeJeɵm҂mR=+4z]D..0K+|zKRz{>^rB{#vA+Nf&ӮÁmKJPt2N^s_7mIߤ#3Uݩj`J 472ǵȉCmȒLinTKz`^;bœ|1)@zΒ ߋ4:LCDPkPsZbw =jmo1˺HЗqG}NJXI ҇T TGK6=㙲V#m0-}?)^!w0*H #OVGyiI9-/e'2?#.+ܽ |ݽCLv'kC.xA-$V|o+HALl qhh[ht"#"vˢ ͿfW]f` լ2?tCzAD,/>䭁{x|thas{(Kҹān?EV ͝TʉJ"%B;?gO H>2_;)L|d,ٲL)sC~-FFKF9'Lv#L4<+[w AD:kxd u^yL̞fKsY">)>ځbD=E}/$_n/bjL?:aމ_hH1t p^﨟BmA3EtĉS\t=4b&eH W#}H1J.ݷq*iz9::|-F g6[Yp ]FW4O|Y=LY GU09Tkd0<zj|5) P)쮠 +'E󬓂D.G }<?RP[G5ǡvpgō A.WŶw0C'i~|7 |2c"庤39D0%yeyʄjVQڷy=׀˖c`3MyX5f (Iz̜2oٟI^E98x3$YʕոMWO)mV`d*vW0>^]^+ w9o/ouuNv OXn ^wԄ@Vex4N#%Js HM )L' 6x{`=@0sesVKp!Vz4T\.tZDD%/p[:DB Z{$LjBB+Ɉi?qp~>H!0'lAH)4eL[6u!\H⴩#== sщTd.;n*y-*B"4}%t*P_O`lN+XlJ݈Wn_t. 2Th븯*D_]9kTdYe#@P-V?.r>K1k[^n5 ᙢI< h#(L~<~$lNh`S*TٯC+*:Ѽ'NU lZk]D[{lZ̿P' - ?)9LHaH#[Jd*8~%luH.oHS/2lOV.zWMcA`<f|\]0ʴXyY^{X[Tor1Z6b' r /&ÙήcIV\3C$j/ffNSQQ*ykMMx\%uH4*yܗ ~>!(GuW1oePfzX5Xl  H݂a y4"uy`i9ilfY۽XؓxEV+4ҐV&H3ի!7fH6;Hp۩DdZzӶ Ch,nI&SJ2&l"'1K8D2'6}{j͙h;!Dbb(oت|-(ې1Z 74SL?%B.PvWݛy'㉏d4/}`j+T{e0d~u35dH׳F]5TN>{a=r ()A"\m0(j(c9 CI>řniGAT$\v{gOdE}"a2c=l'#O=+Џ֮N*w6`>OL?ХT$)uppv*V6>h "Eij0T "TXH&@Q6g#l HgA$Xͬ4p$]{ U&0dǰHKko펈'?Ĭj4q E i+{krn_*t^hE }яעޣ;2~ 88\bYrv핾Mg$ ~s /cN:A 8Xo'5grRJ`&49_G 9qaF$34}C+lZ|y*r; >Ф)Jm[CT6|$0V~8@X#5]7O:f$B5ۍ}e[Yܗp4b:v~˕ qptpvם #GjCN8%;REz| _=5'IIGUvd3tѣ$Ő -GoUǵׄW+a+෣kr`c$ v=:T#]iE|hfSO-vT|(&<0%ezc0s;iɆlAV^Id`0']3`#  QlKׁrv>!'xZP}m]7nH3e"x{ҷN'6F_SSd+[ d)e-UlolML Yt(AyȁlQ1VTۺBZY{+&[?~H- 5+$3~FI$ !6RYF?;O Dh4khpnu3~mi%ӫן7ydj$[W(\Rr2zHe/序Xjr7}&zL,7VN\siUi;bgޱ ,M(TNIzZ_v[.'6Jd}%[ 78h׊bOZ@ “X{~/]w.5bk< ^s5Zٸ_g 7:ۘP& i^Kͦ!g2$cNHEr1QjyG6 "9t Nq'2Y  q0x IlNf W(\f  Hx\9>s] DeT Mv+@SVP`!l D12Ij#[.<",q6 /ѣPߕ€;'٩8$BY~)~c#@m0vǻ<"9H}zU7U5MRRl7f|XOm=,QR] IBS $jo3o{3)\] KZ`͖^eFZL4RMYru} S@l)f鈍V A&.:+Iʖ$ VP䕏q|s]('Aj)Z>:ϵz%= o>fŸ\r>I&'?,%WI*Hr"+[_Ek1;u{uPVSpk1.x$Xq6K)`G \`#V%?f!&Vّt$XlqEYvYHA3g XnN#;>Sj6[fw8Qa a͖0Xu'P9uL '|i5GnRm0f{[$|!<Ô?u:WБ86ƠK 9ws#г o,VK04sEB5%IrfS/|XO[^B7 ;4cn[ÃTu: G>HT3J"ÌXLy8!)/g5ac;.Ыl"{;x -{~c& UDu8VOƬxhec  :o6{KRG,Wz6cUC_'o%i5W 1CXCC}:lZ:7\wmY`N0quG#CDFZ\z)u3 EJu(4$hԆ\? b v⚬m@y\'բIc 'Xn"\/Nڂ'(~S ާ=,Ou>>* *78%> kB8IT^(\?HhYeQy=/} x! L^r1P#c_ Ԅ\q z\1ٯ ow0>amQ@{r‰)Av,?p-rիFѸ9k &"LnoOiv~=R8_+.aGvmw7Re>wY T ʯNh6Y vٓc|JОҸZ.'ڤJ`%VHNJQl(v[o{!bcb ͫ7H}Dʨ,6-4r/\K*JPM ;w? hrS[KbU59uF9'1}ij- SHSX؝QXpWƱZW5e-w|Gqw;z"vsxEɿ:s"WÛioIn`-KS?(+ZJj5ʏ]sKbҬm@ 7 ^C%+V |M=(Zp+Z:N;eY@+@]9(V#_A^QkH[?Y+6)nj 0n0,F>K1LМh}{3){`W[pNXgzם&p׳5f%{,;`.iRo &WnѬZE^R_|~\LQ{0@qtO2.¹nWt|SQ44+x/$Ў"vnH~rδLϜWV`CˉVɹ ۤj"@)W'qqϫ P.Si-,Zsy:fQZk8I[PG0t4ڼ馳}XNGPkfdJedfu8믌poE@~$ K˛˯?fNNw|<юz~% H+ ɭE6LyR/WOj0ʨtZ820q.it[c"-fF U3)+ 3á2ˢ|GW\W- uH8"ZwInRv axty:杔^Ħ\w$a>d{2 ^Ŵp]F& l(FJ2:<~ȌjhHD>< ^8l(M]dAC6Y(wvNb.rr$aQF\*։ԏU .YIe0˴7$ ۧZenMFF܍v&Ad)$ن٤eF]z5Λ 15<iϙy3ĚGdSR hԐy9k!R~Q2dm: K{L~T+bmϵ+=(}$Id ewIy>h*0 DyWBIadnҶ zk T7%0jssɃǏjҫ!sgΪ'd&]piMt[}ULgI!2: %Ѫ~nHIJ#u֝RLVleI?oŘRM,}4y@H~ɷױ0~ 9~lNǷmQ9,-.%++Dkx m`-U!RAYIYS#tI5T-Hsf$R]Ixqd;'Sr n9O81W56 4H|%x"WҲ7{fv[]\L8 rM깏EӘLRK@[V!Izҡp&H*FC(HDOy WGg@Q!M'!k08 ZBOԩ+}Mjpwݻ{\ Y\WT۫ /Ȑn?`B,HÍ8JvmÁe}?XS6kMK{3ڧɴ> Y? fqq9-iM!hPΙxEon4iӨOCկ7Ncn>̔'='jPtsr R,p*!2'N=>ZOVNYmMHMdGnu#+%%)в}ge9@'~|˟V,E-.G7b^?/C >g+- o+{iԟ-+;rp'朓3ұZz ~8 k UUTT_vK3Ȥm\%s r!<%yvvccJ?r5vfCM9}лA:Eץ1"["* ,pL@2=vJ {d& 5q 9FI$J M!IvXZUD{Js A ğ‹<5$$4x].s;J>~^lX<{=Qb~^yF{/ m*{ס$g=Ç (v͔Tr\{x\kܪgT53{wTXֱ8m 3'U7]:$@v_Dž2U|v -}S)e_p!8^Roy="4{,^׍y'{k{k%Xmnv:eluY+nNm ljo47ݟ/A $ܡt:~r?߿? GO/j1|^GNrkjèWA&Hb{pR?M83kBV߿17CT|AVL*A(ҺjOMjh~Atݛ:h~v8>H*ue{머{oʺp Fߧ!j"[:^DpuV ߼Q97ߝtD;{DH7ߑ ;5r^w:2܀NEat~&~ikk3Tǩ۬wt}NȝX7hjo +`Wx7߽eCKit!Z>güoB[Lfw֣RCzet*6v(wťЍͼ@W:>wĠ!` Rkbw 9eŸw6~o[źx*J+Q;г:M*t4]j煞2s 2ᓗ|ƕhX#;"h?*/o.׿*_۳f4rbLUBNV ;` ȹe11\@|YL :> S@#1{|/z:Kj0}=*j ?8EEѐ?;E,N-O*Vgӈ'tkC?5e;tjW~GzquuV[.fBMgeꁳz#ς;>M;S`: %oNf[i7ٱN(IX"`){3ɟy21xlt.lOۀ4o.oC@\gS Re/<׋9`>IgY`%]+eN'$>a1<(w"¹DZ0#t Kxiue"R1w4O֑CLj0@ SZZon4x3ZDߣ;GW)T%T[WF=ɷyMt\:JWzFSU}e*w~ gA1^Mh µ [J_4T?yd3iIe<}}ԖP*wde<@ ~GwMoYI߱]xCYIQt"5P^">ӊE7/xkz15 5ZUVG<'S _ۤ}a/ߊtW߿5`;jDoz`FAou,YE_񰾵 5%!v* Eg~ԉHL L]̾}c;ވ#G$ ]svq#om"Kn yn* #\A E@SlCR9pAF pvj(",x+ VnwfaaPD1k#aaF/TuKǴNHE<1`D  ) u-˭Ug>;͍ߡ<c?swC: I>L`C5L$iFI3dg%CwY"5Gψ  R1 i3Rpapbb$\͛`H[CzmIiOHgC,9_Q]Hߛl=!Ml}%p<9nbO=kS= BWfQoLڻuڻu-ևߟ○ z?{iBV4?J~8i-g^@WvHY p[aUVѨ(Hi>& d,9b= G#Q(Q 6sv7\5Um#i}"nHqu<$i#i:|jy`!d b]%{A?o-Vzl{3򲝊TݎQCd'P . Um'~oF$g 5q8Д}赤k*jv0AzV^(nBo}nm޻{=ZۍT߼X͛v[ _82MF-\[1P;%ߵQ:6F-2۷c9[yG uŪ߷:wz>S[Xy s6i7Uoc{~ \u5sCVt7l'V$nU$nwMns֯ޥSewhNsCǷ7nnΥn-^-qmy0Eb2%L.]P Ԇ}ZsbbQRf'8@b?Ozy]{dُUX @ͅB:]"4aAa{,BzWO2 AX;y 龴>:Aŧ*}à_шm0=ʇ !qvkB>N2e(lRTlᛗb[qeUNPTCDN?$Mhh<% Pk8FL=+ϊLoIǴxC7'el^Gm#,]$Vp?I= .9\X~ TާĖY&> Zgm>] r|J)cƧIRiFۛK6}}ESG߸z0 i\r@ZvE=L%d [b=$O|:(9thME=7a[ ]sTwDtwv=[ͭ_Z[m^u;|A; -^V#m߼ՀՔs7gYPN8 ݩA[s.\.˷]|O2UV4e_5[\0`1zz{+G, zIT θ>s !X G3#B.ܢ#E1IqOK%w\‰ 9R! EHFr$ c/4,*bKdQEM jƜ <,p~5b޺ )&(lּn^ jDでaiÔ ^У6W$B e6nO9#ei%p3R]n2P홆Q&hCS9OC0I\=8 isQinHE`TgF"g5N`ՂF)*E )"seiJ}-|}%<$4$X wB:yfWt)gtpf!d'+G>86NO%^覆2iUO偊Mօ@2.9їjwȻq@t?J0VK(MY lA$,?wqV &ٜ~x2ss|з89n!oir|i.쌿/}]N!5(lڜKpH0gLjW MYI7+x0a"P&yk8>RtYh=@JW"+zsá̐] Yo279gm#ftX7s婘$\VJ\,/7t |X[srNUӛ8lBf^"25]FdS#m]X>9IBb/EBI0u|+| Yk w"ėJ}Őlb$V7Jy rxk5,,(q>m < }ѳ&w^b%^m.EfQ? nxt1ϴK%NY}AUa$h>7v6wJF}1A~>IZ2G&;\\e'K0$Xh\lJ'ii8 /i_3~=;:V>QlskR!)P;g #?O%6Y=)!tkL^ SOV_9 L nx>_׹ !yȞ?q. U0(D;+W_~75dàQ͘afs?;Y(k'HyKbqE[KAzm8>j z  Pj[+8*O{DI-Lv9$&`g.Y칹tXk. Q_ă6w{(=G,봕뺝ꁧIJ|BLY/kLSeH%K*=Iqj<6$ZI Hb%+Mx*Lz]KaBX\Qhg5lZQ&mO5Hϓߞ(l47xb[>ǃ{ ?j/|wCcU>Lθ= hk] 2R$#IJ8`+gX>@إ<ݼ w:(Fe8m\%MJOs-_~'.Fu=N1T&@r}:-gA0'\[ ''p#&1{Υ(e9lY}RZ$x{Q^I'$(׷(KQoȰ`v(1 bgȨ =p 41כ)o?tJ>loca٩͝?;]3/kV(v g YjSWUJ'Q5MV6в-7GR?*dբh4=ﬢ]:F逡)yF 2T7 `ĞaLсjq>;cKef˴Ô|Ľ=UpqFx#h#y̗-b .Ukؽ cpM*(:*}" c xڭw5mJXT6ᅂOj kg=_ηgAso:>bOJvl@V9MwPb۪*pDJE􂁵Ɉñ;wY9I֗fWliЯFѧ!b֔V>s ڻ_I~~fQv6^TWr/Tm¯cG碴?EԡJ ՈQD9AH a3qyWoV]ŌtMtVnWPLtW[=<}+o_}=cҾ=BŸOL..2QAg ^D-?4Vi8qkXڕz,^Jut+/%י5qO-}d0PhZvJ,١D:ˮS"Yo0h(}Kĭ1:{o?PrNvFA/?ԊA.kYX$ͺw|lUxQhŒTj> ,|=G3Za-?ocoiKyu(Q%CAL!&2YA#AbFo@A^&UildB0IjPn0$ ^\d;)at