xref: /openbsd-src/sys/dev/pci/dwiic_pci.c (revision 68462b3fe8563d2e806214046714a0d5c288a0fd)
1 /* $OpenBSD: dwiic_pci.c,v 1.31 2024/09/06 03:52:38 jsg Exp $ */
2 /*
3  * Synopsys DesignWare I2C controller
4  * PCI attachment
5  *
6  * Copyright (c) 2015-2017 joshua stein <jcs@openbsd.org>
7  *
8  * Permission to use, copy, modify, and/or distribute this software for any
9  * purpose with or without fee is hereby granted, provided that the above
10  * copyright notice and this permission notice appear in all copies.
11  *
12  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19  */
20 
21 #include <sys/param.h>
22 #include <sys/systm.h>
23 
24 #include <dev/pci/pcidevs.h>
25 #include <dev/pci/pcireg.h>
26 #include <dev/pci/pcivar.h>
27 
28 #include <dev/ic/dwiicvar.h>
29 
30 /* 13.3: I2C Additional Registers Summary */
31 #define LPSS_RESETS		0x204
32 #define  LPSS_RESETS_I2C	(1 << 0) | (1 << 1)
33 #define  LPSS_RESETS_IDMA	(1 << 2)
34 #define LPSS_ACTIVELTR		0x210
35 #define LPSS_IDLELTR		0x214
36 #define LPSS_CAPS		0x2fc
37 #define  LPSS_CAPS_NO_IDMA	(1 << 8)
38 #define  LPSS_CAPS_TYPE_SHIFT	4
39 #define  LPSS_CAPS_TYPE_MASK	(0xf << LPSS_CAPS_TYPE_SHIFT)
40 
41 int		dwiic_pci_match(struct device *, void *, void *);
42 void		dwiic_pci_attach(struct device *, struct device *, void *);
43 int		dwiic_pci_activate(struct device *, int);
44 void		dwiic_pci_bus_scan(struct device *,
45 		    struct i2cbus_attach_args *, void *);
46 
47 #include "acpi.h"
48 #if NACPI > 0
49 struct aml_node *acpi_pci_match(struct device *dev, struct pci_attach_args *pa);
50 #endif
51 
52 const struct cfattach dwiic_pci_ca = {
53 	sizeof(struct dwiic_softc),
54 	dwiic_pci_match,
55 	dwiic_pci_attach,
56 	NULL,
57 	dwiic_pci_activate,
58 };
59 
60 const struct pci_matchid dwiic_pci_ids[] = {
61 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_100SERIES_I2C0 },
62 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_100SERIES_I2C1 },
63 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_100SERIES_I2C2 },
64 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_100SERIES_I2C3 },
65 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_100SERIES_LP_I2C_1 },
66 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_100SERIES_LP_I2C_2 },
67 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_100SERIES_LP_I2C_3 },
68 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_100SERIES_LP_I2C_4 },
69 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_100SERIES_LP_I2C_5 },
70 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_100SERIES_LP_I2C_6 },
71 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_200SERIES_I2C_1 },
72 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_200SERIES_I2C_2 },
73 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_200SERIES_I2C_3 },
74 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_200SERIES_I2C_4 },
75 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_300SERIES_I2C_1 },
76 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_300SERIES_I2C_2 },
77 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_300SERIES_I2C_3 },
78 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_300SERIES_I2C_4 },
79 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_300SERIES_U_I2C_1 },
80 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_300SERIES_U_I2C_2 },
81 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_300SERIES_U_I2C_3 },
82 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_300SERIES_U_I2C_4 },
83 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_300SERIES_U_I2C_5 },
84 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_300SERIES_U_I2C_6 },
85 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_400SERIES_I2C_1 },
86 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_400SERIES_I2C_2 },
87 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_400SERIES_I2C_3 },
88 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_400SERIES_I2C_4 },
89 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_400SERIES_LP_I2C_1 },
90 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_400SERIES_LP_I2C_2 },
91 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_400SERIES_LP_I2C_3 },
92 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_400SERIES_LP_I2C_4 },
93 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_400SERIES_LP_I2C_5 },
94 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_400SERIES_LP_I2C_6 },
95 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_400SERIES_V_I2C_1 },
96 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_400SERIES_V_I2C_2 },
97 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_400SERIES_V_I2C_3 },
98 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_400SERIES_V_I2C_4 },
99 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_495SERIES_LP_I2C_1 },
100 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_495SERIES_LP_I2C_2 },
101 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_495SERIES_LP_I2C_3 },
102 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_495SERIES_LP_I2C_4 },
103 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_495SERIES_LP_I2C_5 },
104 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_495SERIES_LP_I2C_6 },
105 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_500SERIES_I2C_0 },
106 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_500SERIES_I2C_1 },
107 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_500SERIES_I2C_2 },
108 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_500SERIES_I2C_3 },
109 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_500SERIES_I2C_4 },
110 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_500SERIES_I2C_5 },
111 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_500SERIES_I2C_6 },
112 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_500SERIES_LP_I2C_1 },
113 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_500SERIES_LP_I2C_2 },
114 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_500SERIES_LP_I2C_3 },
115 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_500SERIES_LP_I2C_4 },
116 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_500SERIES_LP_I2C_5 },
117 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_500SERIES_LP_I2C_6 },
118 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_600SERIES_I2C_0 },
119 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_600SERIES_I2C_1 },
120 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_600SERIES_I2C_2 },
121 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_600SERIES_I2C_3 },
122 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_600SERIES_I2C_4 },
123 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_600SERIES_I2C_5 },
124 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_600SERIES_LP_I2C_0 },
125 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_600SERIES_LP_I2C_1 },
126 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_600SERIES_LP_I2C_2 },
127 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_600SERIES_LP_I2C_3 },
128 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_600SERIES_LP_I2C_4 },
129 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_600SERIES_LP_I2C_5 },
130 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_600SERIES_LP_I2C_6 },
131 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_600SERIES_LP_I2C_7 },
132 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_700SERIES_I2C_0 },
133 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_700SERIES_I2C_1 },
134 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_700SERIES_I2C_2 },
135 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_700SERIES_I2C_3 },
136 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_700SERIES_I2C_4 },
137 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_700SERIES_I2C_5 },
138 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_APOLLOLAKE_I2C_1 },
139 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_APOLLOLAKE_I2C_2 },
140 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_APOLLOLAKE_I2C_3 },
141 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_APOLLOLAKE_I2C_4 },
142 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_APOLLOLAKE_I2C_5 },
143 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_APOLLOLAKE_I2C_6 },
144 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_APOLLOLAKE_I2C_7 },
145 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_APOLLOLAKE_I2C_8 },
146 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_GLK_I2C_1 },
147 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_GLK_I2C_2 },
148 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_GLK_I2C_3 },
149 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_GLK_I2C_4 },
150 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_GLK_I2C_5 },
151 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_GLK_I2C_6 },
152 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_GLK_I2C_7 },
153 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_GLK_I2C_8 },
154 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_JSL_I2C_0 },
155 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_JSL_I2C_1 },
156 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_JSL_I2C_2 },
157 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_JSL_I2C_3 },
158 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_JSL_I2C_4 },
159 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_JSL_I2C_5 },
160 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_EHL_SIO_I2C_0 },
161 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_EHL_SIO_I2C_1 },
162 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_EHL_SIO_I2C_2 },
163 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_EHL_SIO_I2C_3 },
164 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_EHL_SIO_I2C_4 },
165 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_EHL_SIO_I2C_5 },
166 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_EHL_SIO_I2C_6 },
167 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_EHL_SIO_I2C_7 },
168 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_ADL_N_I2C_0 },
169 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_ADL_N_I2C_1 },
170 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_ADL_N_I2C_2 },
171 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_ADL_N_I2C_3 },
172 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_ADL_N_I2C_4 },
173 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_ADL_N_I2C_5 },
174 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_ADL_N_I2C_6 },
175 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_ADL_N_I2C_7 },
176 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_MTL_I2C_0 },
177 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_MTL_I2C_1 },
178 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_MTL_I2C_2 },
179 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_MTL_I2C_3 },
180 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_MTL_I2C_4 },
181 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_MTL_I2C_5 },
182 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_LNL_I2C_0 },
183 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_LNL_I2C_1 },
184 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_LNL_I2C_2 },
185 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_LNL_I2C_3 },
186 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_LNL_I2C_4 },
187 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_LNL_I2C_5 },
188 };
189 
190 int
191 dwiic_pci_match(struct device *parent, void *match, void *aux)
192 {
193 	return (pci_matchbyid(aux, dwiic_pci_ids, nitems(dwiic_pci_ids)));
194 }
195 
196 void
197 dwiic_pci_attach(struct device *parent, struct device *self, void *aux)
198 {
199 	struct dwiic_softc *sc = (struct dwiic_softc *)self;
200 	struct pci_attach_args *pa = aux;
201 #if NACPI > 0
202 	struct aml_node *node;
203 #endif
204 	bus_size_t iosize;
205 	pci_intr_handle_t ih;
206 	const char *intrstr = NULL;
207 	uint8_t type;
208 
209 	memcpy(&sc->sc_paa, pa, sizeof(sc->sc_paa));
210 
211 	pci_set_powerstate(pa->pa_pc, pa->pa_tag, PCI_PMCSR_STATE_D0);
212 
213 	if (pci_mapreg_map(pa, PCI_MAPREG_START, PCI_MAPREG_MEM_TYPE_64BIT, 0,
214 	    &sc->sc_iot, &sc->sc_ioh, NULL, &iosize, 0)) {
215 		printf(": can't map mem space\n");
216 		return;
217 	}
218 
219 	sc->sc_caps = bus_space_read_4(sc->sc_iot, sc->sc_ioh, LPSS_CAPS);
220 	type = sc->sc_caps & LPSS_CAPS_TYPE_MASK;
221 	type >>= LPSS_CAPS_TYPE_SHIFT;
222 	if (type != 0) {
223 		printf(": type %d not supported\n", type);
224 		return;
225 	}
226 
227 	/* un-reset - page 958 */
228 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, LPSS_RESETS,
229 	    (LPSS_RESETS_I2C | LPSS_RESETS_IDMA));
230 
231 #if NACPI > 0
232 	/* fetch timing parameters from ACPI, if possible */
233 	node = acpi_pci_match(self, &sc->sc_paa);
234 	if (node != NULL) {
235 		sc->sc_devnode = node;
236 
237 		dwiic_acpi_get_params(sc, "SSCN", &sc->ss_hcnt, &sc->ss_lcnt,
238 		    NULL);
239 		dwiic_acpi_get_params(sc, "FMCN", &sc->fs_hcnt, &sc->fs_lcnt,
240 		    &sc->sda_hold_time);
241 	}
242 #endif
243 
244 	if (dwiic_init(sc)) {
245 		printf(": failed initializing\n");
246 		return;
247 	}
248 
249 	/* leave the controller disabled */
250 	dwiic_write(sc, DW_IC_INTR_MASK, 0);
251 	dwiic_enable(sc, 0);
252 	dwiic_read(sc, DW_IC_CLR_INTR);
253 
254 	/* install interrupt handler */
255 	sc->sc_poll = 1;
256 	if (pci_intr_map(&sc->sc_paa, &ih) == 0) {
257 		intrstr = pci_intr_string(sc->sc_paa.pa_pc, ih);
258 		sc->sc_ih = pci_intr_establish(sc->sc_paa.pa_pc, ih, IPL_BIO,
259 		    dwiic_intr, sc, sc->sc_dev.dv_xname);
260 		if (sc->sc_ih != NULL) {
261 			printf(": %s", intrstr);
262 			sc->sc_poll = 0;
263 		}
264 	}
265 	if (sc->sc_poll)
266 		printf(": polling");
267 
268 	printf("\n");
269 
270 	rw_init(&sc->sc_i2c_lock, "iiclk");
271 
272 	/* setup and attach iic bus */
273 	sc->sc_i2c_tag.ic_cookie = sc;
274 	sc->sc_i2c_tag.ic_acquire_bus = dwiic_i2c_acquire_bus;
275 	sc->sc_i2c_tag.ic_release_bus = dwiic_i2c_release_bus;
276 	sc->sc_i2c_tag.ic_exec = dwiic_i2c_exec;
277 	sc->sc_i2c_tag.ic_intr_establish = dwiic_i2c_intr_establish;
278 	sc->sc_i2c_tag.ic_intr_string = dwiic_i2c_intr_string;
279 
280 	bzero(&sc->sc_iba, sizeof(sc->sc_iba));
281 	sc->sc_iba.iba_name = "iic";
282 	sc->sc_iba.iba_tag = &sc->sc_i2c_tag;
283 	sc->sc_iba.iba_bus_scan = dwiic_pci_bus_scan;
284 	sc->sc_iba.iba_bus_scan_arg = sc;
285 
286 	config_found((struct device *)sc, &sc->sc_iba, iicbus_print);
287 
288 #if NACPI > 0 && !defined(SMALL_KERNEL)
289 	if (sc->sc_devnode) {
290 		sc->sc_devnode->i2c = &sc->sc_i2c_tag;
291 		acpi_register_gsb(acpi_softc, sc->sc_devnode);
292 	}
293 #endif
294 }
295 
296 int
297 dwiic_pci_activate(struct device *self, int act)
298 {
299 	struct dwiic_softc *sc = (struct dwiic_softc *)self;
300 
301 	switch (act) {
302 	case DVACT_RESUME:
303 		DELAY(10000);	/* 10 msec */
304 		bus_space_write_4(sc->sc_iot, sc->sc_ioh, LPSS_RESETS,
305 		    (LPSS_RESETS_I2C | LPSS_RESETS_IDMA));
306 		DELAY(10000);	/* 10 msec */
307 		break;
308 	}
309 	return dwiic_activate(self, act);
310 }
311 
312 void
313 dwiic_pci_bus_scan(struct device *iic, struct i2cbus_attach_args *iba,
314     void *aux)
315 {
316 	struct dwiic_softc *sc = (struct dwiic_softc *)aux;
317 
318 	sc->sc_iic = iic;
319 
320 #if NACPI > 0
321 	if (sc->sc_devnode != NULL)
322 		aml_find_node(sc->sc_devnode, "_HID", dwiic_acpi_found_hid, sc);
323 #endif
324 }
325