Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * This file is subject to the terms and conditions of the GNU General Public | |
3 | * License. See the file "COPYING" in the main directory of this archive | |
4 | * for more details. | |
5 | * | |
6 | * ARC firmware interface defines. | |
7 | * | |
79add627 | 8 | * Copyright (C) 1996 David S. Miller (davem@davemloft.net) |
1da177e4 LT |
9 | * Copyright (C) 1999, 2001 Ralf Baechle (ralf@gnu.org) |
10 | * Copyright (C) 1999 Silicon Graphics, Inc. | |
11 | */ | |
12 | #ifndef _ASM_SGIARCS_H | |
13 | #define _ASM_SGIARCS_H | |
14 | ||
ce6c0a59 TB |
15 | #include <linux/kernel.h> |
16 | ||
1da177e4 | 17 | #include <asm/types.h> |
2f56cfdd | 18 | #include <asm/fw/arc/types.h> |
1da177e4 LT |
19 | |
20 | /* Various ARCS error codes. */ | |
70342287 RB |
21 | #define PROM_ESUCCESS 0x00 |
22 | #define PROM_E2BIG 0x01 | |
23 | #define PROM_EACCESS 0x02 | |
24 | #define PROM_EAGAIN 0x03 | |
25 | #define PROM_EBADF 0x04 | |
26 | #define PROM_EBUSY 0x05 | |
27 | #define PROM_EFAULT 0x06 | |
28 | #define PROM_EINVAL 0x07 | |
29 | #define PROM_EIO 0x08 | |
30 | #define PROM_EISDIR 0x09 | |
31 | #define PROM_EMFILE 0x0a | |
32 | #define PROM_EMLINK 0x0b | |
33 | #define PROM_ENAMETOOLONG 0x0c | |
34 | #define PROM_ENODEV 0x0d | |
35 | #define PROM_ENOENT 0x0e | |
36 | #define PROM_ENOEXEC 0x0f | |
37 | #define PROM_ENOMEM 0x10 | |
38 | #define PROM_ENOSPC 0x11 | |
39 | #define PROM_ENOTDIR 0x12 | |
40 | #define PROM_ENOTTY 0x13 | |
41 | #define PROM_ENXIO 0x14 | |
42 | #define PROM_EROFS 0x15 | |
1da177e4 | 43 | /* SGI ARCS specific errno's. */ |
70342287 RB |
44 | #define PROM_EADDRNOTAVAIL 0x1f |
45 | #define PROM_ETIMEDOUT 0x20 | |
46 | #define PROM_ECONNABORTED 0x21 | |
47 | #define PROM_ENOCONNECT 0x22 | |
1da177e4 LT |
48 | |
49 | /* Device classes, types, and identifiers for prom | |
50 | * device inventory queries. | |
51 | */ | |
52 | enum linux_devclass { | |
53 | system, processor, cache, adapter, controller, peripheral, memory | |
54 | }; | |
55 | ||
56 | enum linux_devtypes { | |
57 | /* Generic stuff. */ | |
58 | Arc, Cpu, Fpu, | |
59 | ||
60 | /* Primary insn and data caches. */ | |
61 | picache, pdcache, | |
62 | ||
63 | /* Secondary insn, data, and combined caches. */ | |
64 | sicache, sdcache, sccache, | |
65 | ||
66 | memdev, eisa_adapter, tc_adapter, scsi_adapter, dti_adapter, | |
67 | multifunc_adapter, dsk_controller, tp_controller, cdrom_controller, | |
68 | worm_controller, serial_controller, net_controller, disp_controller, | |
69 | parallel_controller, ptr_controller, kbd_controller, audio_controller, | |
70 | misc_controller, disk_peripheral, flpy_peripheral, tp_peripheral, | |
71 | modem_peripheral, monitor_peripheral, printer_peripheral, | |
72 | ptr_peripheral, kbd_peripheral, term_peripheral, line_peripheral, | |
73 | net_peripheral, misc_peripheral, anon | |
74 | }; | |
75 | ||
76 | enum linux_identifier { | |
77 | bogus, ronly, removable, consin, consout, input, output | |
78 | }; | |
79 | ||
80 | /* A prom device tree component. */ | |
81 | struct linux_component { | |
70342287 RB |
82 | enum linux_devclass class; /* node class */ |
83 | enum linux_devtypes type; /* node type */ | |
84 | enum linux_identifier iflags; /* node flags */ | |
85 | USHORT vers; /* node version */ | |
86 | USHORT rev; /* node revision */ | |
87 | ULONG key; /* completely magic */ | |
88 | ULONG amask; /* XXX affinity mask??? */ | |
89 | ULONG cdsize; /* size of configuration data */ | |
1da177e4 LT |
90 | ULONG ilen; /* length of string identifier */ |
91 | _PULONG iname; /* string identifier */ | |
92 | }; | |
93 | typedef struct linux_component pcomponent; | |
94 | ||
95 | struct linux_sysid { | |
96 | char vend[8], prod[8]; | |
97 | }; | |
98 | ||
99 | /* ARCS prom memory descriptors. */ | |
100 | enum arcs_memtypes { | |
101 | arcs_eblock, /* exception block */ | |
102 | arcs_rvpage, /* ARCS romvec page */ | |
103 | arcs_fcontig, /* Contiguous and free */ | |
104 | arcs_free, /* Generic free memory */ | |
105 | arcs_bmem, /* Borken memory, don't use */ | |
106 | arcs_prog, /* A loaded program resides here */ | |
107 | arcs_atmp, /* ARCS temporary storage area, wish Sparc OpenBoot told this */ | |
108 | arcs_aperm, /* ARCS permanent storage... */ | |
109 | }; | |
110 | ||
111 | /* ARC has slightly different types than ARCS */ | |
112 | enum arc_memtypes { | |
113 | arc_eblock, /* exception block */ | |
114 | arc_rvpage, /* romvec page */ | |
115 | arc_free, /* Generic free memory */ | |
116 | arc_bmem, /* Borken memory, don't use */ | |
117 | arc_prog, /* A loaded program resides here */ | |
118 | arc_atmp, /* temporary storage area */ | |
119 | arc_aperm, /* permanent storage */ | |
120 | arc_fcontig, /* Contiguous and free */ | |
121 | }; | |
122 | ||
123 | union linux_memtypes { | |
124 | enum arcs_memtypes arcs; | |
125 | enum arc_memtypes arc; | |
126 | }; | |
127 | ||
128 | struct linux_mdesc { | |
129 | union linux_memtypes type; | |
130 | ULONG base; | |
131 | ULONG pages; | |
132 | }; | |
133 | ||
134 | /* Time of day descriptor. */ | |
135 | struct linux_tinfo { | |
136 | unsigned short yr; | |
137 | unsigned short mnth; | |
138 | unsigned short day; | |
139 | unsigned short hr; | |
140 | unsigned short min; | |
141 | unsigned short sec; | |
142 | unsigned short msec; | |
143 | }; | |
144 | ||
145 | /* ARCS virtual dirents. */ | |
146 | struct linux_vdirent { | |
147 | ULONG namelen; | |
148 | unsigned char attr; | |
92a76f6d | 149 | char fname[32]; /* XXX empirical, should be a define */ |
1da177e4 LT |
150 | }; |
151 | ||
152 | /* Other stuff for files. */ | |
153 | enum linux_omode { | |
154 | rdonly, wronly, rdwr, wronly_creat, rdwr_creat, | |
155 | wronly_ssede, rdwr_ssede, dirent, dirent_creat | |
156 | }; | |
157 | ||
158 | enum linux_seekmode { | |
159 | absolute, relative | |
160 | }; | |
161 | ||
162 | enum linux_mountops { | |
163 | media_load, media_unload | |
164 | }; | |
165 | ||
166 | /* This prom has a bolixed design. */ | |
167 | struct linux_bigint { | |
168 | #ifdef __MIPSEL__ | |
169 | u32 lo; | |
170 | s32 hi; | |
171 | #else /* !(__MIPSEL__) */ | |
172 | s32 hi; | |
173 | u32 lo; | |
174 | #endif | |
175 | }; | |
176 | ||
177 | struct linux_finfo { | |
178 | struct linux_bigint begin; | |
179 | struct linux_bigint end; | |
180 | struct linux_bigint cur; | |
181 | enum linux_devtypes dtype; | |
70342287 RB |
182 | unsigned long namelen; |
183 | unsigned char attr; | |
92a76f6d | 184 | char name[32]; /* XXX empirical, should be define */ |
1da177e4 LT |
185 | }; |
186 | ||
187 | /* This describes the vector containing function pointers to the ARC | |
70342287 | 188 | firmware functions. */ |
1da177e4 LT |
189 | struct linux_romvec { |
190 | LONG load; /* Load an executable image. */ | |
191 | LONG invoke; /* Invoke a standalong image. */ | |
192 | LONG exec; /* Load and begin execution of a | |
193 | standalone image. */ | |
194 | LONG halt; /* Halt the machine. */ | |
195 | LONG pdown; /* Power down the machine. */ | |
196 | LONG restart; /* XXX soft reset??? */ | |
197 | LONG reboot; /* Reboot the machine. */ | |
198 | LONG imode; /* Enter PROM interactive mode. */ | |
199 | LONG _unused1; /* Was ReturnFromMain(). */ | |
200 | ||
201 | /* PROM device tree interface. */ | |
202 | LONG next_component; | |
203 | LONG child_component; | |
204 | LONG parent_component; | |
205 | LONG component_data; | |
206 | LONG child_add; | |
207 | LONG comp_del; | |
208 | LONG component_by_path; | |
209 | ||
210 | /* Misc. stuff. */ | |
211 | LONG cfg_save; | |
212 | LONG get_sysid; | |
213 | ||
214 | /* Probing for memory. */ | |
215 | LONG get_mdesc; | |
216 | LONG _unused2; /* was Signal() */ | |
217 | ||
218 | LONG get_tinfo; | |
219 | LONG get_rtime; | |
220 | ||
221 | /* File type operations. */ | |
222 | LONG get_vdirent; | |
223 | LONG open; | |
224 | LONG close; | |
225 | LONG read; | |
226 | LONG get_rstatus; | |
227 | LONG write; | |
228 | LONG seek; | |
229 | LONG mount; | |
230 | ||
231 | /* Dealing with firmware environment variables. */ | |
232 | LONG get_evar; | |
233 | LONG set_evar; | |
234 | ||
235 | LONG get_finfo; | |
236 | LONG set_finfo; | |
237 | ||
238 | /* Miscellaneous. */ | |
239 | LONG cache_flush; | |
240 | LONG TestUnicodeCharacter; /* ARC; not sure if ARCS too */ | |
241 | LONG GetDisplayStatus; | |
242 | }; | |
243 | ||
244 | /* The SGI ARCS parameter block is in a fixed location for standalone | |
245 | * programs to access PROM facilities easily. | |
246 | */ | |
247 | typedef struct _SYSTEM_PARAMETER_BLOCK { | |
248 | ULONG magic; /* magic cookie */ | |
70342287 | 249 | #define PROMBLOCK_MAGIC 0x53435241 |
1da177e4 LT |
250 | |
251 | ULONG len; /* length of parm block */ | |
252 | USHORT ver; /* ARCS firmware version */ | |
253 | USHORT rev; /* ARCS firmware revision */ | |
254 | _PLONG rs_block; /* Restart block. */ | |
255 | _PLONG dbg_block; /* Debug block. */ | |
256 | _PLONG gevect; /* XXX General vector??? */ | |
257 | _PLONG utlbvect; /* XXX UTLB vector??? */ | |
258 | ULONG rveclen; /* Size of romvec struct. */ | |
259 | _PVOID romvec; /* Function interface. */ | |
260 | ULONG pveclen; /* Length of private vector. */ | |
261 | _PVOID pvector; /* Private vector. */ | |
262 | ULONG adap_cnt; /* Adapter count. */ | |
263 | ULONG adap_typ0; /* First adapter type. */ | |
264 | ULONG adap_vcnt0; /* Adapter 0 vector count. */ | |
265 | _PVOID adap_vector; /* Adapter 0 vector ptr. */ | |
266 | ULONG adap_typ1; /* Second adapter type. */ | |
267 | ULONG adap_vcnt1; /* Adapter 1 vector count. */ | |
268 | _PVOID adap_vector1; /* Adapter 1 vector ptr. */ | |
269 | /* More adapter vectors go here... */ | |
270 | } SYSTEM_PARAMETER_BLOCK, *PSYSTEM_PARAMETER_BLOCK; | |
271 | ||
272 | #define PROMBLOCK ((PSYSTEM_PARAMETER_BLOCK) (int)0xA0001000) | |
273 | #define ROMVECTOR ((struct linux_romvec *) (long)(PROMBLOCK)->romvec) | |
274 | ||
275 | /* Cache layout parameter block. */ | |
276 | union linux_cache_key { | |
277 | struct param { | |
278 | #ifdef __MIPSEL__ | |
279 | unsigned short size; | |
280 | unsigned char lsize; | |
281 | unsigned char bsize; | |
282 | #else /* !(__MIPSEL__) */ | |
283 | unsigned char bsize; | |
284 | unsigned char lsize; | |
285 | unsigned short size; | |
286 | #endif | |
287 | } info; | |
288 | unsigned long allinfo; | |
289 | }; | |
290 | ||
291 | /* Configuration data. */ | |
292 | struct linux_cdata { | |
293 | char *name; | |
294 | int mlen; | |
295 | enum linux_devtypes type; | |
296 | }; | |
297 | ||
298 | /* Common SGI ARCS firmware file descriptors. */ | |
70342287 RB |
299 | #define SGIPROM_STDIN 0 |
300 | #define SGIPROM_STDOUT 1 | |
1da177e4 LT |
301 | |
302 | /* Common SGI ARCS firmware file types. */ | |
70342287 RB |
303 | #define SGIPROM_ROFILE 0x01 /* read-only file */ |
304 | #define SGIPROM_HFILE 0x02 /* hidden file */ | |
305 | #define SGIPROM_SFILE 0x04 /* System file */ | |
306 | #define SGIPROM_AFILE 0x08 /* Archive file */ | |
307 | #define SGIPROM_DFILE 0x10 /* Directory file */ | |
308 | #define SGIPROM_DELFILE 0x20 /* Deleted file */ | |
1da177e4 LT |
309 | |
310 | /* SGI ARCS boot record information. */ | |
311 | struct sgi_partition { | |
312 | unsigned char flag; | |
313 | #define SGIPART_UNUSED 0x00 | |
314 | #define SGIPART_ACTIVE 0x80 | |
315 | ||
316 | unsigned char shead, ssect, scyl; /* unused */ | |
317 | unsigned char systype; /* OS type, Irix or NT */ | |
318 | unsigned char ehead, esect, ecyl; /* unused */ | |
319 | unsigned char rsect0, rsect1, rsect2, rsect3; | |
320 | unsigned char tsect0, tsect1, tsect2, tsect3; | |
321 | }; | |
322 | ||
70342287 | 323 | #define SGIBBLOCK_MAGIC 0xaa55 |
1da177e4 LT |
324 | #define SGIBBLOCK_MAXPART 0x0004 |
325 | ||
326 | struct sgi_bootblock { | |
327 | unsigned char _unused[446]; | |
328 | struct sgi_partition partitions[SGIBBLOCK_MAXPART]; | |
329 | unsigned short magic; | |
330 | }; | |
331 | ||
332 | /* BIOS parameter block. */ | |
333 | struct sgi_bparm_block { | |
334 | unsigned short bytes_sect; /* bytes per sector */ | |
335 | unsigned char sect_clust; /* sectors per cluster */ | |
336 | unsigned short sect_resv; /* reserved sectors */ | |
70342287 | 337 | unsigned char nfats; /* # of allocation tables */ |
1da177e4 LT |
338 | unsigned short nroot_dirents; /* # of root directory entries */ |
339 | unsigned short sect_volume; /* sectors in volume */ | |
340 | unsigned char media_type; /* media descriptor */ | |
341 | unsigned short sect_fat; /* sectors per allocation table */ | |
342 | unsigned short sect_track; /* sectors per track */ | |
70342287 RB |
343 | unsigned short nheads; /* # of heads */ |
344 | unsigned short nhsects; /* # of hidden sectors */ | |
1da177e4 LT |
345 | }; |
346 | ||
347 | struct sgi_bsector { | |
70342287 RB |
348 | unsigned char jmpinfo[3]; |
349 | unsigned char manuf_name[8]; | |
1da177e4 LT |
350 | struct sgi_bparm_block info; |
351 | }; | |
352 | ||
353 | /* Debugging block used with SGI symmon symbolic debugger. */ | |
70342287 | 354 | #define SMB_DEBUG_MAGIC 0xfeeddead |
1da177e4 | 355 | struct linux_smonblock { |
70342287 RB |
356 | unsigned long magic; |
357 | void (*handler)(void); /* Breakpoint routine. */ | |
358 | unsigned long dtable_base; /* Base addr of dbg table. */ | |
359 | int (*printf)(const char *fmt, ...); | |
360 | unsigned long btable_base; /* Breakpoint table. */ | |
361 | unsigned long mpflushreqs; /* SMP cache flush request list. */ | |
362 | unsigned long ntab; /* Name table. */ | |
363 | unsigned long stab; /* Symbol table. */ | |
364 | int smax; /* Max # of symbols. */ | |
1da177e4 LT |
365 | }; |
366 | ||
367 | /* | |
368 | * Macros for calling a 32-bit ARC implementation from 64-bit code | |
369 | */ | |
370 | ||
0e2794b0 | 371 | #if defined(CONFIG_64BIT) && defined(CONFIG_FW_ARC32) |
1da177e4 | 372 | |
ce6c0a59 TB |
373 | extern long call_o32(long vec, void *stack, ...); |
374 | ||
375 | extern u64 o32_stk[4096]; | |
376 | #define O32_STK (&o32_stk[ARRAY_SIZE(o32_stk)]) | |
1da177e4 LT |
377 | |
378 | #define ARC_CALL0(dest) \ | |
379 | ({ long __res; \ | |
380 | long __vec = (long) romvec->dest; \ | |
ce6c0a59 TB |
381 | __res = call_o32(__vec, O32_STK); \ |
382 | __res; \ | |
1da177e4 LT |
383 | }) |
384 | ||
21a151d8 | 385 | #define ARC_CALL1(dest, a1) \ |
1da177e4 | 386 | ({ long __res; \ |
ce6c0a59 | 387 | int __a1 = (int) (long) (a1); \ |
1da177e4 | 388 | long __vec = (long) romvec->dest; \ |
ce6c0a59 TB |
389 | __res = call_o32(__vec, O32_STK, __a1); \ |
390 | __res; \ | |
1da177e4 LT |
391 | }) |
392 | ||
21a151d8 | 393 | #define ARC_CALL2(dest, a1, a2) \ |
1da177e4 | 394 | ({ long __res; \ |
ce6c0a59 TB |
395 | int __a1 = (int) (long) (a1); \ |
396 | int __a2 = (int) (long) (a2); \ | |
1da177e4 | 397 | long __vec = (long) romvec->dest; \ |
ce6c0a59 | 398 | __res = call_o32(__vec, O32_STK, __a1, __a2); \ |
1da177e4 LT |
399 | __res; \ |
400 | }) | |
401 | ||
21a151d8 | 402 | #define ARC_CALL3(dest, a1, a2, a3) \ |
1da177e4 | 403 | ({ long __res; \ |
ce6c0a59 TB |
404 | int __a1 = (int) (long) (a1); \ |
405 | int __a2 = (int) (long) (a2); \ | |
406 | int __a3 = (int) (long) (a3); \ | |
1da177e4 | 407 | long __vec = (long) romvec->dest; \ |
ce6c0a59 | 408 | __res = call_o32(__vec, O32_STK, __a1, __a2, __a3); \ |
1da177e4 LT |
409 | __res; \ |
410 | }) | |
411 | ||
21a151d8 | 412 | #define ARC_CALL4(dest, a1, a2, a3, a4) \ |
1da177e4 | 413 | ({ long __res; \ |
ce6c0a59 TB |
414 | int __a1 = (int) (long) (a1); \ |
415 | int __a2 = (int) (long) (a2); \ | |
416 | int __a3 = (int) (long) (a3); \ | |
417 | int __a4 = (int) (long) (a4); \ | |
1da177e4 | 418 | long __vec = (long) romvec->dest; \ |
ce6c0a59 | 419 | __res = call_o32(__vec, O32_STK, __a1, __a2, __a3, __a4); \ |
1da177e4 LT |
420 | __res; \ |
421 | }) | |
422 | ||
ce6c0a59 | 423 | #define ARC_CALL5(dest, a1, a2, a3, a4, a5) \ |
1da177e4 | 424 | ({ long __res; \ |
ce6c0a59 TB |
425 | int __a1 = (int) (long) (a1); \ |
426 | int __a2 = (int) (long) (a2); \ | |
427 | int __a3 = (int) (long) (a3); \ | |
428 | int __a4 = (int) (long) (a4); \ | |
429 | int __a5 = (int) (long) (a5); \ | |
1da177e4 | 430 | long __vec = (long) romvec->dest; \ |
ce6c0a59 | 431 | __res = call_o32(__vec, O32_STK, __a1, __a2, __a3, __a4, __a5); \ |
1da177e4 LT |
432 | __res; \ |
433 | }) | |
434 | ||
0e2794b0 | 435 | #endif /* defined(CONFIG_64BIT) && defined(CONFIG_FW_ARC32) */ |
1da177e4 | 436 | |
0e2794b0 RB |
437 | #if (defined(CONFIG_32BIT) && defined(CONFIG_FW_ARC32)) || \ |
438 | (defined(CONFIG_64BIT) && defined(CONFIG_FW_ARC64)) | |
1da177e4 LT |
439 | |
440 | #define ARC_CALL0(dest) \ | |
441 | ({ long __res; \ | |
442 | long (*__vec)(void) = (void *) romvec->dest; \ | |
443 | \ | |
444 | __res = __vec(); \ | |
445 | __res; \ | |
446 | }) | |
447 | ||
21a151d8 | 448 | #define ARC_CALL1(dest, a1) \ |
1da177e4 LT |
449 | ({ long __res; \ |
450 | long __a1 = (long) (a1); \ | |
451 | long (*__vec)(long) = (void *) romvec->dest; \ | |
452 | \ | |
453 | __res = __vec(__a1); \ | |
454 | __res; \ | |
455 | }) | |
456 | ||
21a151d8 | 457 | #define ARC_CALL2(dest, a1, a2) \ |
1da177e4 LT |
458 | ({ long __res; \ |
459 | long __a1 = (long) (a1); \ | |
460 | long __a2 = (long) (a2); \ | |
461 | long (*__vec)(long, long) = (void *) romvec->dest; \ | |
462 | \ | |
463 | __res = __vec(__a1, __a2); \ | |
464 | __res; \ | |
465 | }) | |
466 | ||
21a151d8 | 467 | #define ARC_CALL3(dest, a1, a2, a3) \ |
1da177e4 LT |
468 | ({ long __res; \ |
469 | long __a1 = (long) (a1); \ | |
470 | long __a2 = (long) (a2); \ | |
471 | long __a3 = (long) (a3); \ | |
70342287 | 472 | long (*__vec)(long, long, long) = (void *) romvec->dest; \ |
1da177e4 LT |
473 | \ |
474 | __res = __vec(__a1, __a2, __a3); \ | |
475 | __res; \ | |
476 | }) | |
477 | ||
21a151d8 | 478 | #define ARC_CALL4(dest, a1, a2, a3, a4) \ |
1da177e4 LT |
479 | ({ long __res; \ |
480 | long __a1 = (long) (a1); \ | |
481 | long __a2 = (long) (a2); \ | |
482 | long __a3 = (long) (a3); \ | |
483 | long __a4 = (long) (a4); \ | |
484 | long (*__vec)(long, long, long, long) = (void *) romvec->dest; \ | |
485 | \ | |
486 | __res = __vec(__a1, __a2, __a3, __a4); \ | |
487 | __res; \ | |
488 | }) | |
489 | ||
21a151d8 | 490 | #define ARC_CALL5(dest, a1, a2, a3, a4, a5) \ |
1da177e4 LT |
491 | ({ long __res; \ |
492 | long __a1 = (long) (a1); \ | |
493 | long __a2 = (long) (a2); \ | |
494 | long __a3 = (long) (a3); \ | |
495 | long __a4 = (long) (a4); \ | |
496 | long __a5 = (long) (a5); \ | |
497 | long (*__vec)(long, long, long, long, long); \ | |
498 | __vec = (void *) romvec->dest; \ | |
499 | \ | |
500 | __res = __vec(__a1, __a2, __a3, __a4, __a5); \ | |
501 | __res; \ | |
502 | }) | |
503 | #endif /* both kernel and ARC either 32-bit or 64-bit */ | |
504 | ||
505 | #endif /* _ASM_SGIARCS_H */ |