summaryrefslogtreecommitdiffstats
path: root/include/linux/mISDNif.h
blob: 536ca12442ca5b0227b7e4c5b03f4038df67d268 (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
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
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
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
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
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
/*
 *
 * Author	Karsten Keil <kkeil@novell.com>
 *
 * Copyright 2008  by Karsten Keil <kkeil@novell.com>
 *
 * This code 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.
 *
 * This code 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.
 *
 */

#ifndef mISDNIF_H
#define mISDNIF_H

#include <stdarg.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/socket.h>

/*
 * ABI Version 32 bit
 *
 * <8 bit> Major version
 *		- changed if any interface become backwards incompatible
 *
 * <8 bit> Minor version
 *              - changed if any interface is extended but backwards compatible
 *
 * <16 bit> Release number
 *              - should be incremented on every checkin
 */
#define	MISDN_MAJOR_VERSION	1
#define	MISDN_MINOR_VERSION	1
#define MISDN_RELEASE		21

/* primitives for information exchange
 * generell format
 * <16  bit  0 >
 * <8  bit command>
 *    BIT 8 = 1 LAYER private
 *    BIT 7 = 1 answer
 *    BIT 6 = 1 DATA
 * <8  bit target layer mask>
 *
 * Layer = 00 is reserved for general commands
   Layer = 01  L2 -> HW
   Layer = 02  HW -> L2
   Layer = 04  L3 -> L2
   Layer = 08  L2 -> L3
 * Layer = FF is reserved for broadcast commands
 */

#define MISDN_CMDMASK		0xff00
#define MISDN_LAYERMASK		0x00ff

/* generell commands */
#define OPEN_CHANNEL		0x0100
#define CLOSE_CHANNEL		0x0200
#define CONTROL_CHANNEL		0x0300
#define CHECK_DATA		0x0400

/* layer 2 -> layer 1 */
#define PH_ACTIVATE_REQ		0x0101
#define PH_DEACTIVATE_REQ	0x0201
#define PH_DATA_REQ		0x2001
#define MPH_ACTIVATE_REQ	0x0501
#define MPH_DEACTIVATE_REQ	0x0601
#define MPH_INFORMATION_REQ	0x0701
#define PH_CONTROL_REQ		0x0801

/* layer 1 -> layer 2 */
#define PH_ACTIVATE_IND		0x0102
#define PH_ACTIVATE_CNF		0x4102
#define PH_DEACTIVATE_IND	0x0202
#define PH_DEACTIVATE_CNF	0x4202
#define PH_DATA_IND		0x2002
#define PH_DATA_E_IND		0x3002
#define MPH_ACTIVATE_IND	0x0502
#define MPH_DEACTIVATE_IND	0x0602
#define MPH_INFORMATION_IND	0x0702
#define PH_DATA_CNF		0x6002
#define PH_CONTROL_IND		0x0802
#define PH_CONTROL_CNF		0x4802

/* layer 3 -> layer 2 */
#define DL_ESTABLISH_REQ	0x1004
#define DL_RELEASE_REQ		0x1104
#define DL_DATA_REQ		0x3004
#define DL_UNITDATA_REQ		0x3104
#define DL_INFORMATION_REQ	0x0004

/* layer 2 -> layer 3 */
#define DL_ESTABLISH_IND	0x1008
#define DL_ESTABLISH_CNF	0x5008
#define DL_RELEASE_IND		0x1108
#define DL_RELEASE_CNF		0x5108
#define DL_DATA_IND		0x3008
#define DL_UNITDATA_IND		0x3108
#define DL_INFORMATION_IND	0x0008

/* intern layer 2 managment */
#define MDL_ASSIGN_REQ		0x1804
#define MDL_ASSIGN_IND		0x1904
#define MDL_REMOVE_REQ		0x1A04
#define MDL_REMOVE_IND		0x1B04
#define MDL_STATUS_UP_IND	0x1C04
#define MDL_STATUS_DOWN_IND	0x1D04
#define MDL_STATUS_UI_IND	0x1E04
#define MDL_ERROR_IND		0x1F04
#define MDL_ERROR_RSP		0x5F04

/* DL_INFORMATION_IND types */
#define DL_INFO_L2_CONNECT	0x0001
#define DL_INFO_L2_REMOVED	0x0002

/* PH_CONTROL types */
/* TOUCH TONE IS 0x20XX  XX "0"..."9", "A","B","C","D","*","#" */
#define DTMF_TONE_VAL		0x2000
#define DTMF_TONE_MASK		0x007F
#define DTMF_TONE_START		0x2100
#define DTMF_TONE_STOP		0x2200
#define DTMF_HFC_COEF		0x4000
#define DSP_CONF_JOIN		0x2403
#define DSP_CONF_SPLIT		0x2404
#define DSP_RECEIVE_OFF		0x2405
#define DSP_RECEIVE_ON		0x2406
#define DSP_ECHO_ON		0x2407
#define DSP_ECHO_OFF		0x2408
#define DSP_MIX_ON		0x2409
#define DSP_MIX_OFF		0x240a
#define DSP_DELAY		0x240b
#define DSP_JITTER		0x240c
#define DSP_TXDATA_ON		0x240d
#define DSP_TXDATA_OFF		0x240e
#define DSP_TX_DEJITTER		0x240f
#define DSP_TX_DEJ_OFF		0x2410
#define DSP_TONE_PATT_ON	0x2411
#define DSP_TONE_PATT_OFF	0x2412
#define DSP_VOL_CHANGE_TX	0x2413
#define DSP_VOL_CHANGE_RX	0x2414
#define DSP_BF_ENABLE_KEY	0x2415
#define DSP_BF_DISABLE		0x2416
#define DSP_BF_ACCEPT		0x2416
#define DSP_BF_REJECT		0x2417
#define DSP_PIPELINE_CFG	0x2418
#define HFC_VOL_CHANGE_TX	0x2601
#define HFC_VOL_CHANGE_RX	0x2602
#define HFC_SPL_LOOP_ON		0x2603
#define HFC_SPL_LOOP_OFF	0x2604
/* for T30 FAX and analog modem */
#define HW_MOD_FRM		0x4000
#define HW_MOD_FRH		0x4001
#define HW_MOD_FTM		0x4002
#define HW_MOD_FTH		0x4003
#define HW_MOD_FTS		0x4004
#define HW_MOD_CONNECT		0x4010
#define HW_MOD_OK		0x4011
#define HW_MOD_NOCARR		0x4012
#define HW_MOD_FCERROR		0x4013
#define HW_MOD_READY		0x4014
#define HW_MOD_LASTDATA		0x4015

/* DSP_TONE_PATT_ON parameter */
#define TONE_OFF			0x0000
#define TONE_GERMAN_DIALTONE		0x0001
#define TONE_GERMAN_OLDDIALTONE		0x0002
#define TONE_AMERICAN_DIALTONE		0x0003
#define TONE_GERMAN_DIALPBX		0x0004
#define TONE_GERMAN_OLDDIALPBX		0x0005
#define TONE_AMERICAN_DIALPBX		0x0006
#define TONE_GERMAN_RINGING		0x0007
#define TONE_GERMAN_OLDRINGING		0x0008
#define TONE_AMERICAN_RINGPBX		0x000b
#define TONE_GERMAN_RINGPBX		0x000c
#define TONE_GERMAN_OLDRINGPBX		0x000d
#define TONE_AMERICAN_RINGING		0x000e
#define TONE_GERMAN_BUSY		0x000f
#define TONE_GERMAN_OLDBUSY		0x0010
#define TONE_AMERICAN_BUSY		0x0011
#define TONE_GERMAN_HANGUP		0x0012
#define TONE_GERMAN_OLDHANGUP		0x0013
#define TONE_AMERICAN_HANGUP		0x0014
#define TONE_SPECIAL_INFO		0x0015
#define TONE_GERMAN_GASSENBESETZT	0x0016
#define TONE_GERMAN_AUFSCHALTTON	0x0016

/* MPH_INFORMATION_IND */
#define L1_SIGNAL_LOS_OFF	0x0010
#define L1_SIGNAL_LOS_ON	0x0011
#define L1_SIGNAL_AIS_OFF	0x0012
#define L1_SIGNAL_AIS_ON	0x0013
#define L1_SIGNAL_RDI_OFF	0x0014
#define L1_SIGNAL_RDI_ON	0x0015
#define L1_SIGNAL_SLIP_RX	0x0020
#define L1_SIGNAL_SLIP_TX	0x0021

/*
 * protocol ids
 * D channel 1-31
 * B channel 33 - 63
 */

#define ISDN_P_NONE		0
#define ISDN_P_BASE		0
#define ISDN_P_TE_S0		0x01
#define ISDN_P_NT_S0  		0x02
#define ISDN_P_TE_E1		0x03
#define ISDN_P_NT_E1  		0x04
#define ISDN_P_TE_UP0		0x05
#define ISDN_P_NT_UP0		0x06

#define IS_ISDN_P_TE(p) ((p == ISDN_P_TE_S0) || (p == ISDN_P_TE_E1) || \
				(p == ISDN_P_TE_UP0) || (p == ISDN_P_LAPD_TE))
#define IS_ISDN_P_NT(p) ((p == ISDN_P_NT_S0) || (p == ISDN_P_NT_E1) || \
				(p == ISDN_P_NT_UP0) || (p == ISDN_P_LAPD_NT))
#define IS_ISDN_P_S0(p) ((p == ISDN_P_TE_S0) || (p == ISDN_P_NT_S0))
#define IS_ISDN_P_E1(p) ((p == ISDN_P_TE_E1) || (p == ISDN_P_NT_E1))
#define IS_ISDN_P_UP0(p) ((p == ISDN_P_TE_UP0) || (p == ISDN_P_NT_UP0))


#define ISDN_P_LAPD_TE		0x10
#define	ISDN_P_LAPD_NT		0x11

#define ISDN_P_B_MASK		0x1f
#define ISDN_P_B_START		0x20

#define ISDN_P_B_RAW		0x21
#define ISDN_P_B_HDLC		0x22
#define ISDN_P_B_X75SLP		0x23
#define ISDN_P_B_L2DTMF		0x24
#define ISDN_P_B_L2DSP		0x25
#define ISDN_P_B_L2DSPHDLC	0x26
#define ISDN_P_B_T30_FAX	0x27
#define ISDN_P_B_MODEM_ASYNC	0x28

#define OPTION_L2_PMX		1
#define OPTION_L2_PTP		2
#define OPTION_L2_FIXEDTEI	3
#define OPTION_L2_CLEANUP	4
#define OPTION_L1_HOLD		5

/* should be in sync with linux/kobject.h:KOBJ_NAME_LEN */
#define MISDN_MAX_IDLEN		20

struct mISDNhead {
	unsigned int	prim;
	unsigned int	id;
}  __attribute__((packed));

#define MISDN_HEADER_LEN	sizeof(struct mISDNhead)
#define MAX_DATA_SIZE		2048
#define MAX_DATA_MEM		(MAX_DATA_SIZE + MISDN_HEADER_LEN)
#define MAX_DFRAME_LEN		260

#define MISDN_ID_ADDR_MASK	0xFFFF
#define MISDN_ID_TEI_MASK	0xFF00
#define MISDN_ID_SAPI_MASK	0x00FF
#define MISDN_ID_TEI_ANY	0x7F00

#define MISDN_ID_ANY		0xFFFF
#define MISDN_ID_NONE		0xFFFE

#define GROUP_TEI		127
#define TEI_SAPI		63
#define CTRL_SAPI		0

#define MISDN_MAX_CHANNEL	127
#define MISDN_CHMAP_SIZE	((MISDN_MAX_CHANNEL + 1) >> 3)

#define SOL_MISDN	0

struct sockaddr_mISDN {
	sa_family_t    family;
	unsigned char	dev;
	unsigned char	channel;
	unsigned char	sapi;
	unsigned char	tei;
};

struct mISDNversion {
	unsigned char	major;
	unsigned char	minor;
	unsigned short	release;
};

struct mISDN_devinfo {
	u_int			id;
	u_int			Dprotocols;
	u_int			Bprotocols;
	u_int			protocol;
	u_char			channelmap[MISDN_CHMAP_SIZE];
	u_int			nrbchan;
	char			name[MISDN_MAX_IDLEN];
};

struct mISDN_devrename {
	u_int			id;
	char			name[MISDN_MAX_IDLEN]; /* new name */
};

/* MPH_INFORMATION_REQ payload */
struct ph_info_ch {
	__u32 protocol;
	__u64 Flags;
};

struct ph_info_dch {
	struct ph_info_ch ch;
	__u16 state;
	__u16 num_bch;
};

struct ph_info {
	struct ph_info_dch dch;
	struct ph_info_ch  bch[];
};

/* timer device ioctl */
#define IMADDTIMER	_IOR('I', 64, int)
#define IMDELTIMER	_IOR('I', 65, int)

/* socket ioctls */
#define	IMGETVERSION	_IOR('I', 66, int)
#define	IMGETCOUNT	_IOR('I', 67, int)
#define IMGETDEVINFO	_IOR('I', 68, int)
#define IMCTRLREQ	_IOR('I', 69, int)
#define IMCLEAR_L2	_IOR('I', 70, int)
#define IMSETDEVNAME	_IOR('I', 71, struct mISDN_devrename)
#define IMHOLD_L1	_IOR('I', 72, int)

static inline int
test_channelmap(u_int nr, u_char *map)
{
	if (nr <= MISDN_MAX_CHANNEL)
		return map[nr >> 3] & (1 << (nr & 7));
	else
		return 0;
}

static inline void
set_channelmap(u_int nr, u_char *map)
{
	map[nr >> 3] |= (1 << (nr & 7));
}

static inline void
clear_channelmap(u_int nr, u_char *map)
{
	map[nr >> 3] &= ~(1 << (nr & 7));
}

/* CONTROL_CHANNEL parameters */
#define MISDN_CTRL_GETOP		0x0000
#define MISDN_CTRL_LOOP			0x0001
#define MISDN_CTRL_CONNECT		0x0002
#define MISDN_CTRL_DISCONNECT		0x0004
#define MISDN_CTRL_PCMCONNECT		0x0010
#define MISDN_CTRL_PCMDISCONNECT	0x0020
#define MISDN_CTRL_SETPEER		0x0040
#define MISDN_CTRL_UNSETPEER		0x0080
#define MISDN_CTRL_RX_OFF		0x0100
#define MISDN_CTRL_FILL_EMPTY		0x0200
#define MISDN_CTRL_GETPEER		0x0400
#define MISDN_CTRL_HW_FEATURES_OP	0x2000
#define MISDN_CTRL_HW_FEATURES		0x2001
#define MISDN_CTRL_HFC_OP		0x4000
#define MISDN_CTRL_HFC_PCM_CONN		0x4001
#define MISDN_CTRL_HFC_PCM_DISC		0x4002
#define MISDN_CTRL_HFC_CONF_JOIN	0x4003
#define MISDN_CTRL_HFC_CONF_SPLIT	0x4004
#define MISDN_CTRL_HFC_RECEIVE_OFF	0x4005
#define MISDN_CTRL_HFC_RECEIVE_ON	0x4006
#define MISDN_CTRL_HFC_ECHOCAN_ON 	0x4007
#define MISDN_CTRL_HFC_ECHOCAN_OFF 	0x4008
#define MISDN_CTRL_HFC_WD_INIT		0x4009
#define MISDN_CTRL_HFC_WD_RESET		0x400A

/* socket options */
#define MISDN_TIME_STAMP		0x0001

struct mISDN_ctrl_req {
	int		op;
	int		channel;
	int		p1;
	int		p2;
};

/* muxer options */
#define MISDN_OPT_ALL		1
#define MISDN_OPT_TEIMGR	2

#ifdef __KERNEL__
#include <linux/list.h>
#include <linux/skbuff.h>
#include <linux/net.h>
#include <net/sock.h>
#include <linux/completion.h>

#define DEBUG_CORE		0x000000ff
#define DEBUG_CORE_FUNC		0x00000002
#define DEBUG_SOCKET		0x00000004
#define DEBUG_MANAGER		0x00000008
#define DEBUG_SEND_ERR		0x00000010
#define DEBUG_MSG_THREAD	0x00000020
#define DEBUG_QUEUE_FUNC	0x00000040
#define DEBUG_L1		0x0000ff00
#define DEBUG_L1_FSM		0x00000200
#define DEBUG_L2		0x00ff0000
#define DEBUG_L2_FSM		0x00020000
#define DEBUG_L2_CTRL		0x00040000
#define DEBUG_L2_RECV		0x00080000
#define DEBUG_L2_TEI		0x00100000
#define DEBUG_L2_TEIFSM		0x00200000
#define DEBUG_TIMER		0x01000000
#define DEBUG_CLOCK		0x02000000

#define mISDN_HEAD_P(s)		((struct mISDNhead *)&s->cb[0])
#define mISDN_HEAD_PRIM(s)	(((struct mISDNhead *)&s->cb[0])->prim)
#define mISDN_HEAD_ID(s)	(((struct mISDNhead *)&s->cb[0])->id)

/* socket states */
#define MISDN_OPEN	1
#define MISDN_BOUND	2
#define MISDN_CLOSED	3

struct mISDNchannel;
struct mISDNdevice;
struct mISDNstack;
struct mISDNclock;

struct channel_req {
	u_int			protocol;
	struct sockaddr_mISDN	adr;
	struct mISDNchannel	*ch;
};

typedef	int	(ctrl_func_t)(struct mISDNchannel *, u_int, void *);
typedef	int	(send_func_t)(struct mISDNchannel *, struct sk_buff *);
typedef int	(create_func_t)(struct channel_req *);

struct Bprotocol {
	struct list_head	list;
	char			*name;
	u_int			Bprotocols;
	create_func_t		*create;
};

struct mISDNchannel {
	struct list_head	list;
	u_int			protocol;
	u_int			nr;
	u_long			opt;
	u_int			addr;
	struct mISDNstack	*st;
	struct mISDNchannel	*peer;
	send_func_t		*send;
	send_func_t		*recv;
	ctrl_func_t		*ctrl;
};

struct mISDN_sock_list {
	struct hlist_head	head;
	rwlock_t		lock;
};

struct mISDN_sock {
	struct sock		sk;
	struct mISDNchannel	ch;
	u_int			cmask;
	struct mISDNdevice	*dev;
};



struct mISDNdevice {
	struct mISDNchannel	D;
	u_int			id;
	u_int			Dprotocols;
	u_int			Bprotocols;
	u_int			nrbchan;
	u_char			channelmap[MISDN_CHMAP_SIZE];
	struct list_head	bchannels;
	struct mISDNchannel	*teimgr;
	struct device		dev;
};

struct mISDNstack {
	u_long			status;
	struct mISDNdevice	*dev;
	struct task_struct	*thread;
	struct completion	*notify;
	wait_queue_head_t	workq;
	struct sk_buff_head	msgq;
	struct list_head	layer2;
	struct mISDNchannel	*layer1;
	struct mISDNchannel	own;
	struct mutex		lmutex; /* protect lists */
	struct mISDN_sock_list	l1sock;
#ifdef MISDN_MSG_STATS
	u_int			msg_cnt;
	u_int			sleep_cnt;
	u_int			stopped_cnt;
#endif
};

typedef	int	(clockctl_func_t)(void *, int);

struct	mISDNclock {
	struct list_head	list;
	char			name[64];
	int			pri;
	clockctl_func_t		*ctl;
	void			*priv;
};

/* global alloc/queue functions */

static inline struct sk_buff *
mI_alloc_skb(unsigned int len, gfp_t gfp_mask)
{
	struct sk_buff	*skb;

	skb = alloc_skb(len + MISDN_HEADER_LEN, gfp_mask);
	if (likely(skb))
		skb_reserve(skb, MISDN_HEADER_LEN);
	return skb;
}

static inline struct sk_buff *
_alloc_mISDN_skb(u_int prim, u_int id, u_int len, void *dp, gfp_t gfp_mask)
{
	struct sk_buff	*skb = mI_alloc_skb(len, gfp_mask);
	struct mISDNhead *hh;

	if (!skb)
		return NULL;
	if (len)
		memcpy(skb_put(skb, len), dp, len);
	hh = mISDN_HEAD_P(skb);
	hh->prim = prim;
	hh->id = id;
	return skb;
}

static inline void
_queue_data(struct mISDNchannel *ch, u_int prim,
    u_int id, u_int len, void *dp, gfp_t gfp_mask)
{
	struct sk_buff		*skb;

	if (!ch->peer)
		return;
	skb = _alloc_mISDN_skb(prim, id, len, dp, gfp_mask);
	if (!skb)
		return;
	if (ch->recv(ch->peer, skb))
		dev_kfree_skb(skb);
}

/* global register/unregister functions */

extern int	mISDN_register_device(struct mISDNdevice *,
					struct device *parent, char *name);
extern void	mISDN_unregister_device(struct mISDNdevice *);
extern int	mISDN_register_Bprotocol(struct Bprotocol *);
extern void	mISDN_unregister_Bprotocol(struct Bprotocol *);
extern struct mISDNclock *mISDN_register_clock(char *, int, clockctl_func_t *,
						void *);
extern void	mISDN_unregister_clock(struct mISDNclock *);

static inline struct mISDNdevice *dev_to_mISDN(struct device *dev)
{
	if (dev)
		return dev_get_drvdata(dev);
	else
		return NULL;
}

extern void	set_channel_address(struct mISDNchannel *, u_int, u_int);
extern void	mISDN_clock_update(struct mISDNclock *, int, struct timeval *);
extern unsigned short mISDN_clock_get(void);

#endif /* __KERNEL__ */
#endif /* mISDNIF_H */