1 /* ------------------------------------------------------------------------- */
2 /* i2c-algo-bit.c i2c driver algorithms for bit-shift adapters		     */
3 /* ------------------------------------------------------------------------- */
4 /*   Copyright (C) 1995-2000 Simon G. Vogl
5 
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10 
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15 
16     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.		     */
19 /* ------------------------------------------------------------------------- */
20 
21 /* With some changes from Ky�sti M�lkki <kmalkki@cc.hut.fi> and even
22    Frodo Looijaard <frodol@dds.nl> */
23 
24 /* $Id: i2c-algo-bit.c,v 1.30 2001/07/29 02:44:25 mds Exp $ */
25 
26 #include <linux/kernel.h>
27 #include <linux/module.h>
28 #include <linux/delay.h>
29 #include <linux/slab.h>
30 #include <linux/init.h>
31 #include <linux/errno.h>
32 #include <linux/sched.h>
33 #include <linux/i2c.h>
34 #include <linux/i2c-algo-bit.h>
35 
36 
37 /* ----- global defines ----------------------------------------------- */
38 #define DEB(x) if (i2c_debug>=1) x;
39 #define DEB2(x) if (i2c_debug>=2) x;
40 #define DEBSTAT(x) if (i2c_debug>=3) x; /* print several statistical values*/
41 #define DEBPROTO(x) if (i2c_debug>=9) { x; }
42  	/* debug the protocol by showing transferred bits */
43 
44 /* debugging - slow down transfer to have a look at the data .. 	*/
45 /* I use this with two leds&resistors, each one connected to sda,scl 	*/
46 /* respectively. This makes sure that the algorithm works. Some chips   */
47 /* might not like this, as they have an internal timeout of some mils	*/
48 /*
49 #define SLO_IO      jif=jiffies;while(time_before_eq(jiffies, jif+i2c_table[minor].veryslow))\
50                         if (need_resched) schedule();
51 */
52 
53 
54 /* ----- global variables ---------------------------------------------	*/
55 
56 #ifdef SLO_IO
57 	int jif;
58 #endif
59 
60 /* module parameters:
61  */
62 static int i2c_debug;
63 static int bit_test;	/* see if the line-setting functions work	*/
64 static int bit_scan;	/* have a look at what's hanging 'round		*/
65 
66 /* --- setting states on the bus with the right timing: ---------------	*/
67 
68 #define setsda(adap,val) adap->setsda(adap->data, val)
69 #define setscl(adap,val) adap->setscl(adap->data, val)
70 #define getsda(adap) adap->getsda(adap->data)
71 #define getscl(adap) adap->getscl(adap->data)
72 
sdalo(struct i2c_algo_bit_data * adap)73 static inline void sdalo(struct i2c_algo_bit_data *adap)
74 {
75 	setsda(adap,0);
76 	udelay(adap->udelay);
77 }
78 
sdahi(struct i2c_algo_bit_data * adap)79 static inline void sdahi(struct i2c_algo_bit_data *adap)
80 {
81 	setsda(adap,1);
82 	udelay(adap->udelay);
83 }
84 
scllo(struct i2c_algo_bit_data * adap)85 static inline void scllo(struct i2c_algo_bit_data *adap)
86 {
87 	setscl(adap,0);
88 	udelay(adap->udelay);
89 #ifdef SLO_IO
90 	SLO_IO
91 #endif
92 }
93 
94 /*
95  * Raise scl line, and do checking for delays. This is necessary for slower
96  * devices.
97  */
sclhi(struct i2c_algo_bit_data * adap)98 static inline int sclhi(struct i2c_algo_bit_data *adap)
99 {
100 	int start=jiffies;
101 
102 	setscl(adap,1);
103 
104 	udelay(adap->udelay);
105 
106 	/* Not all adapters have scl sense line... */
107 	if (adap->getscl == NULL )
108 		return 0;
109 
110  	while (! getscl(adap) ) {
111  		/* the hw knows how to read the clock line,
112  		 * so we wait until it actually gets high.
113  		 * This is safer as some chips may hold it low
114  		 * while they are processing data internally.
115  		 */
116 		setscl(adap,1);
117 		if (time_after_eq(jiffies, start+adap->timeout)) {
118 			return -ETIMEDOUT;
119 		}
120 		if (current->need_resched)
121 			schedule();
122 	}
123 	DEBSTAT(printk(KERN_DEBUG "needed %ld jiffies\n", jiffies-start));
124 #ifdef SLO_IO
125 	SLO_IO
126 #endif
127 	return 0;
128 }
129 
130 
131 /* --- other auxiliary functions --------------------------------------	*/
i2c_start(struct i2c_algo_bit_data * adap)132 static void i2c_start(struct i2c_algo_bit_data *adap)
133 {
134 	/* assert: scl, sda are high */
135 	DEBPROTO(printk("S "));
136 	sdalo(adap);
137 	scllo(adap);
138 }
139 
i2c_repstart(struct i2c_algo_bit_data * adap)140 static void i2c_repstart(struct i2c_algo_bit_data *adap)
141 {
142 	/* scl, sda may not be high */
143 	DEBPROTO(printk(" Sr "));
144 	setsda(adap,1);
145 	setscl(adap,1);
146 	udelay(adap->udelay);
147 
148 	sdalo(adap);
149 	scllo(adap);
150 }
151 
152 
i2c_stop(struct i2c_algo_bit_data * adap)153 static void i2c_stop(struct i2c_algo_bit_data *adap)
154 {
155 	DEBPROTO(printk("P\n"));
156 	/* assert: scl is low */
157 	sdalo(adap);
158 	sclhi(adap);
159 	sdahi(adap);
160 }
161 
162 
163 
164 /* send a byte without start cond., look for arbitration,
165    check ackn. from slave */
166 /* returns:
167  * 1 if the device acknowledged
168  * 0 if the device did not ack
169  * -ETIMEDOUT if an error occurred (while raising the scl line)
170  */
i2c_outb(struct i2c_adapter * i2c_adap,char c)171 static int i2c_outb(struct i2c_adapter *i2c_adap, char c)
172 {
173 	int i;
174 	int sb;
175 	int ack;
176 	struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
177 
178 	/* assert: scl is low */
179 	DEB2(printk(KERN_DEBUG " i2c_outb:%2.2X\n",c&0xff));
180 	for ( i=7 ; i>=0 ; i-- ) {
181 		sb = c & ( 1 << i );
182 		setsda(adap,sb);
183 		udelay(adap->udelay);
184 		DEBPROTO(printk(KERN_DEBUG "%d",sb!=0));
185 		if (sclhi(adap)<0) { /* timed out */
186 			sdahi(adap); /* we don't want to block the net */
187 			return -ETIMEDOUT;
188 		};
189 		/* do arbitration here:
190 		 * if ( sb && ! getsda(adap) ) -> ouch! Get out of here.
191 		 */
192 		setscl(adap, 0 );
193 		udelay(adap->udelay);
194 	}
195 	sdahi(adap);
196 	if (sclhi(adap)<0){ /* timeout */
197 		return -ETIMEDOUT;
198 	};
199 	/* read ack: SDA should be pulled down by slave */
200 	ack=getsda(adap);	/* ack: sda is pulled low ->success.	 */
201 	DEB2(printk(KERN_DEBUG " i2c_outb: getsda() =  0x%2.2x\n", ~ack ));
202 
203 	DEBPROTO( printk(KERN_DEBUG "[%2.2x]",c&0xff) );
204 	DEBPROTO(if (0==ack){ printk(KERN_DEBUG " A ");} else printk(KERN_DEBUG " NA ") );
205 	scllo(adap);
206 	return 0==ack;		/* return 1 if device acked	 */
207 	/* assert: scl is low (sda undef) */
208 }
209 
210 
i2c_inb(struct i2c_adapter * i2c_adap)211 static int i2c_inb(struct i2c_adapter *i2c_adap)
212 {
213 	/* read byte via i2c port, without start/stop sequence	*/
214 	/* acknowledge is sent in i2c_read.			*/
215 	int i;
216 	unsigned char indata=0;
217 	struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
218 
219 	/* assert: scl is low */
220 	DEB2(printk(KERN_DEBUG "i2c_inb.\n"));
221 
222 	sdahi(adap);
223 	for (i=0;i<8;i++) {
224 		if (sclhi(adap)<0) { /* timeout */
225 			return -ETIMEDOUT;
226 		};
227 		indata *= 2;
228 		if ( getsda(adap) )
229 			indata |= 0x01;
230 		scllo(adap);
231 	}
232 	/* assert: scl is low */
233 	DEBPROTO(printk(KERN_DEBUG " 0x%02x", indata & 0xff));
234 	return (int) (indata & 0xff);
235 }
236 
237 /*
238  * Sanity check for the adapter hardware - check the reaction of
239  * the bus lines only if it seems to be idle.
240  */
test_bus(struct i2c_algo_bit_data * adap,char * name)241 static int test_bus(struct i2c_algo_bit_data *adap, char* name) {
242 	int scl,sda;
243 	sda=getsda(adap);
244 	if (adap->getscl==NULL) {
245 		printk("i2c-algo-bit.o: Warning: Adapter can't read from clock line - skipping test.\n");
246 		return 0;
247 	}
248 	scl=getscl(adap);
249 	printk("i2c-algo-bit.o: Adapter: %s scl: %d  sda: %d -- testing...\n",
250 	       name,getscl(adap),getsda(adap));
251 	if (!scl || !sda ) {
252 		printk("i2c-algo-bit.o: %s seems to be busy.\n",name);
253 		goto bailout;
254 	}
255 	sdalo(adap);
256 	printk("i2c-algo-bit.o:1 scl: %d  sda: %d \n",getscl(adap),
257 	       getsda(adap));
258 	if ( 0 != getsda(adap) ) {
259 		printk("i2c-algo-bit.o: %s SDA stuck high!\n",name);
260 		sdahi(adap);
261 		goto bailout;
262 	}
263 	if ( 0 == getscl(adap) ) {
264 		printk("i2c-algo-bit.o: %s SCL unexpected low while pulling SDA low!\n",
265 			name);
266 		goto bailout;
267 	}
268 	sdahi(adap);
269 	printk("i2c-algo-bit.o:2 scl: %d  sda: %d \n",getscl(adap),
270 	       getsda(adap));
271 	if ( 0 == getsda(adap) ) {
272 		printk("i2c-algo-bit.o: %s SDA stuck low!\n",name);
273 		sdahi(adap);
274 		goto bailout;
275 	}
276 	if ( 0 == getscl(adap) ) {
277 		printk("i2c-algo-bit.o: %s SCL unexpected low while SDA high!\n",
278 		       name);
279 	goto bailout;
280 	}
281 	scllo(adap);
282 	printk("i2c-algo-bit.o:3 scl: %d  sda: %d \n",getscl(adap),
283 	       getsda(adap));
284 	if ( 0 != getscl(adap) ) {
285 		printk("i2c-algo-bit.o: %s SCL stuck high!\n",name);
286 		sclhi(adap);
287 		goto bailout;
288 	}
289 	if ( 0 == getsda(adap) ) {
290 		printk("i2c-algo-bit.o: %s SDA unexpected low while pulling SCL low!\n",
291 			name);
292 		goto bailout;
293 	}
294 	sclhi(adap);
295 	printk("i2c-algo-bit.o:4 scl: %d  sda: %d \n",getscl(adap),
296 	       getsda(adap));
297 	if ( 0 == getscl(adap) ) {
298 		printk("i2c-algo-bit.o: %s SCL stuck low!\n",name);
299 		sclhi(adap);
300 		goto bailout;
301 	}
302 	if ( 0 == getsda(adap) ) {
303 		printk("i2c-algo-bit.o: %s SDA unexpected low while SCL high!\n",
304 			name);
305 		goto bailout;
306 	}
307 	printk("i2c-algo-bit.o: %s passed test.\n",name);
308 	return 0;
309 bailout:
310 	sdahi(adap);
311 	sclhi(adap);
312 	return -ENODEV;
313 }
314 
315 /* ----- Utility functions
316  */
317 
318 /* try_address tries to contact a chip for a number of
319  * times before it gives up.
320  * return values:
321  * 1 chip answered
322  * 0 chip did not answer
323  * -x transmission error
324  */
try_address(struct i2c_adapter * i2c_adap,unsigned char addr,int retries)325 static inline int try_address(struct i2c_adapter *i2c_adap,
326 		       unsigned char addr, int retries)
327 {
328 	struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
329 	int i,ret = -1;
330 	for (i=0;i<=retries;i++) {
331 		ret = i2c_outb(i2c_adap,addr);
332 		if (ret==1)
333 			break;	/* success! */
334 		i2c_stop(adap);
335 		udelay(5/*adap->udelay*/);
336 		if (i==retries)  /* no success */
337 			break;
338 		i2c_start(adap);
339 		udelay(adap->udelay);
340 	}
341 	DEB2(if (i) printk(KERN_DEBUG "i2c-algo-bit.o: needed %d retries for %d\n",
342 	                   i,addr));
343 	return ret;
344 }
345 
sendbytes(struct i2c_adapter * i2c_adap,const char * buf,int count)346 static int sendbytes(struct i2c_adapter *i2c_adap,const char *buf, int count)
347 {
348 	struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
349 	char c;
350 	const char *temp = buf;
351 	int retval;
352 	int wrcount=0;
353 
354 	while (count > 0) {
355 		c = *temp;
356 		DEB2(printk(KERN_DEBUG "i2c-algo-bit.o: %s sendbytes: writing %2.2X\n",
357 			    i2c_adap->name, c&0xff));
358 		retval = i2c_outb(i2c_adap,c);
359 		if (retval>0) {
360 			count--;
361 			temp++;
362 			wrcount++;
363 		} else { /* arbitration or no acknowledge */
364 			printk(KERN_ERR "i2c-algo-bit.o: %s sendbytes: error - bailout.\n",
365 			       i2c_adap->name);
366 			i2c_stop(adap);
367 			return (retval<0)? retval : -EFAULT;
368 			        /* got a better one ?? */
369 		}
370 	}
371 	return wrcount;
372 }
373 
readbytes(struct i2c_adapter * i2c_adap,char * buf,int count)374 static inline int readbytes(struct i2c_adapter *i2c_adap,char *buf,int count)
375 {
376 	char *temp = buf;
377 	int inval;
378 	int rdcount=0;   	/* counts bytes read */
379 	struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
380 
381 	while (count > 0) {
382 		inval = i2c_inb(i2c_adap);
383 		if (inval>=0) {
384 			*temp = inval;
385 			rdcount++;
386 		} else {   /* read timed out */
387 			printk(KERN_ERR "i2c-algo-bit.o: readbytes: i2c_inb timed out.\n");
388 			break;
389 		}
390 
391 		if ( count > 1 ) {		/* send ack */
392 			sdalo(adap);
393 			DEBPROTO(printk(" Am "));
394 		} else {
395 			sdahi(adap);	/* neg. ack on last byte */
396 			DEBPROTO(printk(" NAm "));
397 		}
398 		if (sclhi(adap)<0) {	/* timeout */
399 			sdahi(adap);
400 			printk(KERN_ERR "i2c-algo-bit.o: readbytes: Timeout at ack\n");
401 			return -ETIMEDOUT;
402 		};
403 		scllo(adap);
404 		sdahi(adap);
405 		temp++;
406 		count--;
407 	}
408 	return rdcount;
409 }
410 
411 /* doAddress initiates the transfer by generating the start condition (in
412  * try_address) and transmits the address in the necessary format to handle
413  * reads, writes as well as 10bit-addresses.
414  * returns:
415  *  0 everything went okay, the chip ack'ed
416  * -x an error occurred (like: -EREMOTEIO if the device did not answer, or
417  *	-ETIMEDOUT, for example if the lines are stuck...)
418  */
bit_doAddress(struct i2c_adapter * i2c_adap,struct i2c_msg * msg,int retries)419 static inline int bit_doAddress(struct i2c_adapter *i2c_adap,
420                                 struct i2c_msg *msg, int retries)
421 {
422 	unsigned short flags = msg->flags;
423 	struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
424 
425 	unsigned char addr;
426 	int ret;
427 	if ( (flags & I2C_M_TEN)  ) {
428 		/* a ten bit address */
429 		addr = 0xf0 | (( msg->addr >> 7) & 0x03);
430 		DEB2(printk(KERN_DEBUG "addr0: %d\n",addr));
431 		/* try extended address code...*/
432 		ret = try_address(i2c_adap, addr, retries);
433 		if (ret!=1) {
434 			printk(KERN_ERR "died at extended address code.\n");
435 			return -EREMOTEIO;
436 		}
437 		/* the remaining 8 bit address */
438 		ret = i2c_outb(i2c_adap,msg->addr & 0x7f);
439 		if (ret != 1) {
440 			/* the chip did not ack / xmission error occurred */
441 			printk(KERN_ERR "died at 2nd address code.\n");
442 			return -EREMOTEIO;
443 		}
444 		if ( flags & I2C_M_RD ) {
445 			i2c_repstart(adap);
446 			/* okay, now switch into reading mode */
447 			addr |= 0x01;
448 			ret = try_address(i2c_adap, addr, retries);
449 			if (ret!=1) {
450 				printk(KERN_ERR "died at extended address code.\n");
451 				return -EREMOTEIO;
452 			}
453 		}
454 	} else {		/* normal 7bit address	*/
455 		addr = ( msg->addr << 1 );
456 		if (flags & I2C_M_RD )
457 			addr |= 1;
458 		if (flags & I2C_M_REV_DIR_ADDR )
459 			addr ^= 1;
460 		ret = try_address(i2c_adap, addr, retries);
461 		if (ret!=1) {
462 			return -EREMOTEIO;
463 		}
464 	}
465 	return 0;
466 }
467 
bit_xfer(struct i2c_adapter * i2c_adap,struct i2c_msg msgs[],int num)468 static int bit_xfer(struct i2c_adapter *i2c_adap,
469 		    struct i2c_msg msgs[], int num)
470 {
471 	struct i2c_msg *pmsg;
472 	struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
473 
474 	int i,ret;
475 
476 	i2c_start(adap);
477 	for (i=0;i<num;i++) {
478 		pmsg = &msgs[i];
479 		if (!(pmsg->flags & I2C_M_NOSTART)) {
480 			if (i) {
481 				i2c_repstart(adap);
482 			}
483 			ret = bit_doAddress(i2c_adap,pmsg,i2c_adap->retries);
484 			if (ret != 0) {
485 				DEB2(printk(KERN_DEBUG "i2c-algo-bit.o: NAK from device addr %2.2x msg #%d\n",
486 					msgs[i].addr,i));
487 				return (ret<0) ? ret : -EREMOTEIO;
488 			}
489 		}
490 		if (pmsg->flags & I2C_M_RD ) {
491 			/* read bytes into buffer*/
492 			ret = readbytes(i2c_adap,pmsg->buf,pmsg->len);
493 			DEB2(printk(KERN_DEBUG "i2c-algo-bit.o: read %d bytes.\n",ret));
494 			if (ret < pmsg->len ) {
495 				return (ret<0)? ret : -EREMOTEIO;
496 			}
497 		} else {
498 			/* write bytes from buffer */
499 			ret = sendbytes(i2c_adap,pmsg->buf,pmsg->len);
500 			DEB2(printk(KERN_DEBUG "i2c-algo-bit.o: wrote %d bytes.\n",ret));
501 			if (ret < pmsg->len ) {
502 				return (ret<0) ? ret : -EREMOTEIO;
503 			}
504 		}
505 	}
506 	i2c_stop(adap);
507 	return num;
508 }
509 
algo_control(struct i2c_adapter * adapter,unsigned int cmd,unsigned long arg)510 static int algo_control(struct i2c_adapter *adapter,
511 	unsigned int cmd, unsigned long arg)
512 {
513 	return 0;
514 }
515 
bit_func(struct i2c_adapter * adap)516 static u32 bit_func(struct i2c_adapter *adap)
517 {
518 	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL |
519 	       I2C_FUNC_10BIT_ADDR | I2C_FUNC_PROTOCOL_MANGLING;
520 }
521 
522 
523 /* -----exported algorithm data: -------------------------------------	*/
524 
525 static struct i2c_algorithm i2c_bit_algo = {
526 	.name		= "Bit-shift algorithm",
527 	.id		= I2C_ALGO_BIT,
528 	.master_xfer	= bit_xfer,
529 	.algo_control	= algo_control,
530 	.functionality	= bit_func,
531 };
532 
533 /*
534  * registering functions to load algorithms at runtime
535  */
i2c_bit_add_bus(struct i2c_adapter * adap)536 int i2c_bit_add_bus(struct i2c_adapter *adap)
537 {
538 	int i;
539 	struct i2c_algo_bit_data *bit_adap = adap->algo_data;
540 
541 	if (bit_test) {
542 		int ret = test_bus(bit_adap, adap->name);
543 		if (ret<0)
544 			return -ENODEV;
545 	}
546 
547 	DEB2(printk(KERN_DEBUG "i2c-algo-bit.o: hw routines for %s registered.\n",
548 	            adap->name));
549 
550 	/* register new adapter to i2c module... */
551 
552 	adap->id |= i2c_bit_algo.id;
553 	adap->algo = &i2c_bit_algo;
554 
555 	adap->timeout = 100;	/* default values, should	*/
556 	adap->retries = 3;	/* be replaced by defines	*/
557 
558 	/* scan bus */
559 	if (bit_scan) {
560 		int ack;
561 		printk(KERN_INFO " i2c-algo-bit.o: scanning bus %s.\n",
562 		       adap->name);
563 		for (i = 0x00; i < 0xff; i+=2) {
564 			i2c_start(bit_adap);
565 			ack = i2c_outb(adap,i);
566 			i2c_stop(bit_adap);
567 			if (ack>0) {
568 				printk("(%02x)",i>>1);
569 			} else
570 				printk(".");
571 		}
572 		printk("\n");
573 	}
574 
575 #ifdef MODULE
576 	MOD_INC_USE_COUNT;
577 #endif
578 
579 	return i2c_add_adapter(adap);
580 }
581 
582 
i2c_bit_del_bus(struct i2c_adapter * adap)583 int i2c_bit_del_bus(struct i2c_adapter *adap)
584 {
585 	int res;
586 
587 	if ((res = i2c_del_adapter(adap)) < 0)
588 		return res;
589 
590 	DEB2(printk("i2c-algo-bit.o: adapter unregistered: %s\n",adap->name));
591 
592 #ifdef MODULE
593 	MOD_DEC_USE_COUNT;
594 #endif
595 	return 0;
596 }
597 
i2c_algo_bit_init(void)598 int __init i2c_algo_bit_init (void)
599 {
600 	printk(KERN_INFO "i2c-algo-bit.o: i2c bit algorithm module\n");
601 	return 0;
602 }
603 
604 EXPORT_SYMBOL(i2c_bit_add_bus);
605 EXPORT_SYMBOL(i2c_bit_del_bus);
606 
607 #ifdef MODULE
608 MODULE_AUTHOR("Simon G. Vogl <simon@tk.uni-linz.ac.at>");
609 MODULE_DESCRIPTION("I2C-Bus bit-banging algorithm");
610 MODULE_LICENSE("GPL");
611 
612 MODULE_PARM(bit_test, "i");
613 MODULE_PARM(bit_scan, "i");
614 MODULE_PARM(i2c_debug,"i");
615 
616 MODULE_PARM_DESC(bit_test, "Test the lines of the bus to see if it is stuck");
617 MODULE_PARM_DESC(bit_scan, "Scan for active chips on the bus");
618 MODULE_PARM_DESC(i2c_debug,
619             "debug level - 0 off; 1 normal; 2,3 more verbose; 9 bit-protocol");
620 
init_module(void)621 int init_module(void)
622 {
623 	return i2c_algo_bit_init();
624 }
625 
cleanup_module(void)626 void cleanup_module(void)
627 {
628 }
629 #endif
630