Pull vector-domain into release branch
[sfrench/cifs-2.6.git] / drivers / media / video / tda9887.c
1 #include <linux/module.h>
2 #include <linux/moduleparam.h>
3 #include <linux/kernel.h>
4 #include <linux/i2c.h>
5 #include <linux/types.h>
6 #include <linux/videodev.h>
7 #include <linux/init.h>
8 #include <linux/errno.h>
9 #include <linux/slab.h>
10 #include <linux/delay.h>
11
12 #include <media/v4l2-common.h>
13 #include <media/tuner.h>
14 #include "tuner-driver.h"
15
16
17 /* Chips:
18    TDA9885 (PAL, NTSC)
19    TDA9886 (PAL, SECAM, NTSC)
20    TDA9887 (PAL, SECAM, NTSC, FM Radio)
21
22    Used as part of several tuners
23 */
24
25 #define tda9887_info(fmt, arg...) do {\
26         printk(KERN_INFO "%s %d-%04x: " fmt, t->i2c.name, \
27                         i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
28 #define tda9887_dbg(fmt, arg...) do {\
29         if (tuner_debug) \
30                 printk(KERN_INFO "%s %d-%04x: " fmt, t->i2c.name, \
31                         i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
32
33 struct tda9887_priv {
34         unsigned char      data[4];
35 };
36
37 /* ---------------------------------------------------------------------- */
38
39 #define UNSET       (-1U)
40
41 struct tvnorm {
42         v4l2_std_id       std;
43         char              *name;
44         unsigned char     b;
45         unsigned char     c;
46         unsigned char     e;
47 };
48
49 /* ---------------------------------------------------------------------- */
50
51 //
52 // TDA defines
53 //
54
55 //// first reg (b)
56 #define cVideoTrapBypassOFF     0x00    // bit b0
57 #define cVideoTrapBypassON      0x01    // bit b0
58
59 #define cAutoMuteFmInactive     0x00    // bit b1
60 #define cAutoMuteFmActive       0x02    // bit b1
61
62 #define cIntercarrier           0x00    // bit b2
63 #define cQSS                    0x04    // bit b2
64
65 #define cPositiveAmTV           0x00    // bit b3:4
66 #define cFmRadio                0x08    // bit b3:4
67 #define cNegativeFmTV           0x10    // bit b3:4
68
69
70 #define cForcedMuteAudioON      0x20    // bit b5
71 #define cForcedMuteAudioOFF     0x00    // bit b5
72
73 #define cOutputPort1Active      0x00    // bit b6
74 #define cOutputPort1Inactive    0x40    // bit b6
75
76 #define cOutputPort2Active      0x00    // bit b7
77 #define cOutputPort2Inactive    0x80    // bit b7
78
79
80 //// second reg (c)
81 #define cDeemphasisOFF          0x00    // bit c5
82 #define cDeemphasisON           0x20    // bit c5
83
84 #define cDeemphasis75           0x00    // bit c6
85 #define cDeemphasis50           0x40    // bit c6
86
87 #define cAudioGain0             0x00    // bit c7
88 #define cAudioGain6             0x80    // bit c7
89
90 #define cTopMask                0x1f    // bit c0:4
91 #define cTopDefault             0x10    // bit c0:4
92
93 //// third reg (e)
94 #define cAudioIF_4_5             0x00    // bit e0:1
95 #define cAudioIF_5_5             0x01    // bit e0:1
96 #define cAudioIF_6_0             0x02    // bit e0:1
97 #define cAudioIF_6_5             0x03    // bit e0:1
98
99
100 #define cVideoIF_58_75           0x00    // bit e2:4
101 #define cVideoIF_45_75           0x04    // bit e2:4
102 #define cVideoIF_38_90           0x08    // bit e2:4
103 #define cVideoIF_38_00           0x0C    // bit e2:4
104 #define cVideoIF_33_90           0x10    // bit e2:4
105 #define cVideoIF_33_40           0x14    // bit e2:4
106 #define cRadioIF_45_75           0x18    // bit e2:4
107 #define cRadioIF_38_90           0x1C    // bit e2:4
108
109
110 #define cTunerGainNormal         0x00    // bit e5
111 #define cTunerGainLow            0x20    // bit e5
112
113 #define cGating_18               0x00    // bit e6
114 #define cGating_36               0x40    // bit e6
115
116 #define cAgcOutON                0x80    // bit e7
117 #define cAgcOutOFF               0x00    // bit e7
118
119 /* ---------------------------------------------------------------------- */
120
121 static struct tvnorm tvnorms[] = {
122         {
123                 .std   = V4L2_STD_PAL_BG | V4L2_STD_PAL_H | V4L2_STD_PAL_N,
124                 .name  = "PAL-BGHN",
125                 .b     = ( cNegativeFmTV  |
126                            cQSS           ),
127                 .c     = ( cDeemphasisON  |
128                            cDeemphasis50  |
129                            cTopDefault),
130                 .e     = ( cGating_36     |
131                            cAudioIF_5_5   |
132                            cVideoIF_38_90 ),
133         },{
134                 .std   = V4L2_STD_PAL_I,
135                 .name  = "PAL-I",
136                 .b     = ( cNegativeFmTV  |
137                            cQSS           ),
138                 .c     = ( cDeemphasisON  |
139                            cDeemphasis50  |
140                            cTopDefault),
141                 .e     = ( cGating_36     |
142                            cAudioIF_6_0   |
143                            cVideoIF_38_90 ),
144         },{
145                 .std   = V4L2_STD_PAL_DK,
146                 .name  = "PAL-DK",
147                 .b     = ( cNegativeFmTV  |
148                            cQSS           ),
149                 .c     = ( cDeemphasisON  |
150                            cDeemphasis50  |
151                            cTopDefault),
152                 .e     = ( cGating_36     |
153                            cAudioIF_6_5   |
154                            cVideoIF_38_90 ),
155         },{
156                 .std   = V4L2_STD_PAL_M | V4L2_STD_PAL_Nc,
157                 .name  = "PAL-M/Nc",
158                 .b     = ( cNegativeFmTV  |
159                            cQSS           ),
160                 .c     = ( cDeemphasisON  |
161                            cDeemphasis75  |
162                            cTopDefault),
163                 .e     = ( cGating_36     |
164                            cAudioIF_4_5   |
165                            cVideoIF_45_75 ),
166         },{
167                 .std   = V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H,
168                 .name  = "SECAM-BGH",
169                 .b     = ( cPositiveAmTV  |
170                            cQSS           ),
171                 .c     = ( cTopDefault),
172                 .e     = ( cGating_36     |
173                            cAudioIF_5_5   |
174                            cVideoIF_38_90 ),
175         },{
176                 .std   = V4L2_STD_SECAM_L,
177                 .name  = "SECAM-L",
178                 .b     = ( cPositiveAmTV  |
179                            cQSS           ),
180                 .c     = ( cTopDefault),
181                 .e     = ( cGating_36     |
182                            cAudioIF_6_5   |
183                            cVideoIF_38_90 ),
184         },{
185                 .std   = V4L2_STD_SECAM_LC,
186                 .name  = "SECAM-L'",
187                 .b     = ( cOutputPort2Inactive |
188                            cPositiveAmTV  |
189                            cQSS           ),
190                 .c     = ( cTopDefault),
191                 .e     = ( cGating_36     |
192                            cAudioIF_6_5   |
193                            cVideoIF_33_90 ),
194         },{
195                 .std   = V4L2_STD_SECAM_DK,
196                 .name  = "SECAM-DK",
197                 .b     = ( cNegativeFmTV  |
198                            cQSS           ),
199                 .c     = ( cDeemphasisON  |
200                            cDeemphasis50  |
201                            cTopDefault),
202                 .e     = ( cGating_36     |
203                            cAudioIF_6_5   |
204                            cVideoIF_38_90 ),
205         },{
206                 .std   = V4L2_STD_NTSC_M | V4L2_STD_NTSC_M_KR,
207                 .name  = "NTSC-M",
208                 .b     = ( cNegativeFmTV  |
209                            cQSS           ),
210                 .c     = ( cDeemphasisON  |
211                            cDeemphasis75  |
212                            cTopDefault),
213                 .e     = ( cGating_36     |
214                            cAudioIF_4_5   |
215                            cVideoIF_45_75 ),
216         },{
217                 .std   = V4L2_STD_NTSC_M_JP,
218                 .name  = "NTSC-M-JP",
219                 .b     = ( cNegativeFmTV  |
220                            cQSS           ),
221                 .c     = ( cDeemphasisON  |
222                            cDeemphasis50  |
223                            cTopDefault),
224                 .e     = ( cGating_36     |
225                            cAudioIF_4_5   |
226                            cVideoIF_58_75 ),
227         }
228 };
229
230 static struct tvnorm radio_stereo = {
231         .name = "Radio Stereo",
232         .b    = ( cFmRadio       |
233                   cQSS           ),
234         .c    = ( cDeemphasisOFF |
235                   cAudioGain6    |
236                   cTopDefault),
237         .e    = ( cTunerGainLow  |
238                   cAudioIF_5_5   |
239                   cRadioIF_38_90 ),
240 };
241
242 static struct tvnorm radio_mono = {
243         .name = "Radio Mono",
244         .b    = ( cFmRadio       |
245                   cQSS           ),
246         .c    = ( cDeemphasisON  |
247                   cDeemphasis75  |
248                   cTopDefault),
249         .e    = ( cTunerGainLow  |
250                   cAudioIF_5_5   |
251                   cRadioIF_38_90 ),
252 };
253
254 /* ---------------------------------------------------------------------- */
255
256 static void dump_read_message(struct tuner *t, unsigned char *buf)
257 {
258         static char *afc[16] = {
259                 "- 12.5 kHz",
260                 "- 37.5 kHz",
261                 "- 62.5 kHz",
262                 "- 87.5 kHz",
263                 "-112.5 kHz",
264                 "-137.5 kHz",
265                 "-162.5 kHz",
266                 "-187.5 kHz [min]",
267                 "+187.5 kHz [max]",
268                 "+162.5 kHz",
269                 "+137.5 kHz",
270                 "+112.5 kHz",
271                 "+ 87.5 kHz",
272                 "+ 62.5 kHz",
273                 "+ 37.5 kHz",
274                 "+ 12.5 kHz",
275         };
276         tda9887_info("read: 0x%2x\n", buf[0]);
277         tda9887_info("  after power on : %s\n", (buf[0] & 0x01) ? "yes" : "no");
278         tda9887_info("  afc            : %s\n", afc[(buf[0] >> 1) & 0x0f]);
279         tda9887_info("  fmif level     : %s\n", (buf[0] & 0x20) ? "high" : "low");
280         tda9887_info("  afc window     : %s\n", (buf[0] & 0x40) ? "in" : "out");
281         tda9887_info("  vfi level      : %s\n", (buf[0] & 0x80) ? "high" : "low");
282 }
283
284 static void dump_write_message(struct tuner *t, unsigned char *buf)
285 {
286         static char *sound[4] = {
287                 "AM/TV",
288                 "FM/radio",
289                 "FM/TV",
290                 "FM/radio"
291         };
292         static char *adjust[32] = {
293                 "-16", "-15", "-14", "-13", "-12", "-11", "-10", "-9",
294                 "-8",  "-7",  "-6",  "-5",  "-4",  "-3",  "-2",  "-1",
295                 "0",   "+1",  "+2",  "+3",  "+4",  "+5",  "+6",  "+7",
296                 "+8",  "+9",  "+10", "+11", "+12", "+13", "+14", "+15"
297         };
298         static char *deemph[4] = {
299                 "no", "no", "75", "50"
300         };
301         static char *carrier[4] = {
302                 "4.5 MHz",
303                 "5.5 MHz",
304                 "6.0 MHz",
305                 "6.5 MHz / AM"
306         };
307         static char *vif[8] = {
308                 "58.75 MHz",
309                 "45.75 MHz",
310                 "38.9 MHz",
311                 "38.0 MHz",
312                 "33.9 MHz",
313                 "33.4 MHz",
314                 "45.75 MHz + pin13",
315                 "38.9 MHz + pin13",
316         };
317         static char *rif[4] = {
318                 "44 MHz",
319                 "52 MHz",
320                 "52 MHz",
321                 "44 MHz",
322         };
323
324         tda9887_info("write: byte B 0x%02x\n",buf[1]);
325         tda9887_info("  B0   video mode      : %s\n",
326                (buf[1] & 0x01) ? "video trap" : "sound trap");
327         tda9887_info("  B1   auto mute fm    : %s\n",
328                (buf[1] & 0x02) ? "yes" : "no");
329         tda9887_info("  B2   carrier mode    : %s\n",
330                (buf[1] & 0x04) ? "QSS" : "Intercarrier");
331         tda9887_info("  B3-4 tv sound/radio  : %s\n",
332                sound[(buf[1] & 0x18) >> 3]);
333         tda9887_info("  B5   force mute audio: %s\n",
334                (buf[1] & 0x20) ? "yes" : "no");
335         tda9887_info("  B6   output port 1   : %s\n",
336                (buf[1] & 0x40) ? "high (inactive)" : "low (active)");
337         tda9887_info("  B7   output port 2   : %s\n",
338                (buf[1] & 0x80) ? "high (inactive)" : "low (active)");
339
340         tda9887_info("write: byte C 0x%02x\n",buf[2]);
341         tda9887_info("  C0-4 top adjustment  : %s dB\n", adjust[buf[2] & 0x1f]);
342         tda9887_info("  C5-6 de-emphasis     : %s\n", deemph[(buf[2] & 0x60) >> 5]);
343         tda9887_info("  C7   audio gain      : %s\n",
344                (buf[2] & 0x80) ? "-6" : "0");
345
346         tda9887_info("write: byte E 0x%02x\n",buf[3]);
347         tda9887_info("  E0-1 sound carrier   : %s\n",
348                carrier[(buf[3] & 0x03)]);
349         tda9887_info("  E6   l pll gating   : %s\n",
350                (buf[3] & 0x40) ? "36" : "13");
351
352         if (buf[1] & 0x08) {
353                 /* radio */
354                 tda9887_info("  E2-4 video if        : %s\n",
355                        rif[(buf[3] & 0x0c) >> 2]);
356                 tda9887_info("  E7   vif agc output  : %s\n",
357                        (buf[3] & 0x80)
358                        ? ((buf[3] & 0x10) ? "fm-agc radio" : "sif-agc radio")
359                        : "fm radio carrier afc");
360         } else {
361                 /* video */
362                 tda9887_info("  E2-4 video if        : %s\n",
363                        vif[(buf[3] & 0x1c) >> 2]);
364                 tda9887_info("  E5   tuner gain      : %s\n",
365                        (buf[3] & 0x80)
366                        ? ((buf[3] & 0x20) ? "external" : "normal")
367                        : ((buf[3] & 0x20) ? "minimum"  : "normal"));
368                 tda9887_info("  E7   vif agc output  : %s\n",
369                        (buf[3] & 0x80)
370                        ? ((buf[3] & 0x20)
371                           ? "pin3 port, pin22 vif agc out"
372                           : "pin22 port, pin3 vif acg ext in")
373                        : "pin3+pin22 port");
374         }
375         tda9887_info("--\n");
376 }
377
378 /* ---------------------------------------------------------------------- */
379
380 static int tda9887_set_tvnorm(struct tuner *t, char *buf)
381 {
382         struct tvnorm *norm = NULL;
383         int i;
384
385         if (t->mode == V4L2_TUNER_RADIO) {
386                 if (t->audmode == V4L2_TUNER_MODE_MONO)
387                         norm = &radio_mono;
388                 else
389                         norm = &radio_stereo;
390         } else {
391                 for (i = 0; i < ARRAY_SIZE(tvnorms); i++) {
392                         if (tvnorms[i].std & t->std) {
393                                 norm = tvnorms+i;
394                                 break;
395                         }
396                 }
397         }
398         if (NULL == norm) {
399                 tda9887_dbg("Unsupported tvnorm entry - audio muted\n");
400                 return -1;
401         }
402
403         tda9887_dbg("configure for: %s\n",norm->name);
404         buf[1] = norm->b;
405         buf[2] = norm->c;
406         buf[3] = norm->e;
407         return 0;
408 }
409
410 static unsigned int port1  = UNSET;
411 static unsigned int port2  = UNSET;
412 static unsigned int qss    = UNSET;
413 static unsigned int adjust = UNSET;
414
415 module_param(port1, int, 0644);
416 module_param(port2, int, 0644);
417 module_param(qss, int, 0644);
418 module_param(adjust, int, 0644);
419
420 static int tda9887_set_insmod(struct tuner *t, char *buf)
421 {
422         if (UNSET != port1) {
423                 if (port1)
424                         buf[1] |= cOutputPort1Inactive;
425                 else
426                         buf[1] &= ~cOutputPort1Inactive;
427         }
428         if (UNSET != port2) {
429                 if (port2)
430                         buf[1] |= cOutputPort2Inactive;
431                 else
432                         buf[1] &= ~cOutputPort2Inactive;
433         }
434
435         if (UNSET != qss) {
436                 if (qss)
437                         buf[1] |= cQSS;
438                 else
439                         buf[1] &= ~cQSS;
440         }
441
442         if (adjust >= 0x00 && adjust < 0x20) {
443                 buf[2] &= ~cTopMask;
444                 buf[2] |= adjust;
445         }
446         return 0;
447 }
448
449 static int tda9887_set_config(struct tuner *t, char *buf)
450 {
451         if (t->tda9887_config & TDA9887_PORT1_ACTIVE)
452                 buf[1] &= ~cOutputPort1Inactive;
453         if (t->tda9887_config & TDA9887_PORT1_INACTIVE)
454                 buf[1] |= cOutputPort1Inactive;
455         if (t->tda9887_config & TDA9887_PORT2_ACTIVE)
456                 buf[1] &= ~cOutputPort2Inactive;
457         if (t->tda9887_config & TDA9887_PORT2_INACTIVE)
458                 buf[1] |= cOutputPort2Inactive;
459
460         if (t->tda9887_config & TDA9887_QSS)
461                 buf[1] |= cQSS;
462         if (t->tda9887_config & TDA9887_INTERCARRIER)
463                 buf[1] &= ~cQSS;
464
465         if (t->tda9887_config & TDA9887_AUTOMUTE)
466                 buf[1] |= cAutoMuteFmActive;
467         if (t->tda9887_config & TDA9887_DEEMPHASIS_MASK) {
468                 buf[2] &= ~0x60;
469                 switch (t->tda9887_config & TDA9887_DEEMPHASIS_MASK) {
470                 case TDA9887_DEEMPHASIS_NONE:
471                         buf[2] |= cDeemphasisOFF;
472                         break;
473                 case TDA9887_DEEMPHASIS_50:
474                         buf[2] |= cDeemphasisON | cDeemphasis50;
475                         break;
476                 case TDA9887_DEEMPHASIS_75:
477                         buf[2] |= cDeemphasisON | cDeemphasis75;
478                         break;
479                 }
480         }
481         if (t->tda9887_config & TDA9887_TOP_SET) {
482                 buf[2] &= ~cTopMask;
483                 buf[2] |= (t->tda9887_config >> 8) & cTopMask;
484         }
485         if ((t->tda9887_config & TDA9887_INTERCARRIER_NTSC) && (t->std & V4L2_STD_NTSC))
486                 buf[1] &= ~cQSS;
487         if (t->tda9887_config & TDA9887_GATING_18)
488                 buf[3] &= ~cGating_36;
489
490         if (t->tda9887_config & TDA9887_GAIN_NORMAL) {
491                 radio_stereo.e &= ~cTunerGainLow;
492                 radio_mono.e &= ~cTunerGainLow;
493         }
494
495         return 0;
496 }
497
498 /* ---------------------------------------------------------------------- */
499
500 static int tda9887_status(struct tuner *t)
501 {
502         unsigned char buf[1];
503         int rc;
504
505         memset(buf,0,sizeof(buf));
506         if (1 != (rc = i2c_master_recv(&t->i2c,buf,1)))
507                 tda9887_info("i2c i/o error: rc == %d (should be 1)\n",rc);
508         dump_read_message(t, buf);
509         return 0;
510 }
511
512 static void tda9887_configure(struct i2c_client *client)
513 {
514         struct tuner *t = i2c_get_clientdata(client);
515         struct tda9887_priv *priv = t->priv;
516         int rc;
517
518         memset(priv->data,0,sizeof(priv->data));
519         tda9887_set_tvnorm(t,priv->data);
520
521         /* A note on the port settings:
522            These settings tend to depend on the specifics of the board.
523            By default they are set to inactive (bit value 1) by this driver,
524            overwriting any changes made by the tvnorm. This means that it
525            is the responsibility of the module using the tda9887 to set
526            these values in case of changes in the tvnorm.
527            In many cases port 2 should be made active (0) when selecting
528            SECAM-L, and port 2 should remain inactive (1) for SECAM-L'.
529
530            For the other standards the tda9887 application note says that
531            the ports should be set to active (0), but, again, that may
532            differ depending on the precise hardware configuration.
533          */
534         priv->data[1] |= cOutputPort1Inactive;
535         priv->data[1] |= cOutputPort2Inactive;
536
537         tda9887_set_config(t,priv->data);
538         tda9887_set_insmod(t,priv->data);
539
540         if (t->mode == T_STANDBY) {
541                 priv->data[1] |= cForcedMuteAudioON;
542         }
543
544         tda9887_dbg("writing: b=0x%02x c=0x%02x e=0x%02x\n",
545                 priv->data[1],priv->data[2],priv->data[3]);
546         if (tuner_debug > 1)
547                 dump_write_message(t, priv->data);
548
549         if (4 != (rc = i2c_master_send(&t->i2c,priv->data,4)))
550                 tda9887_info("i2c i/o error: rc == %d (should be 4)\n",rc);
551
552         if (tuner_debug > 2) {
553                 msleep_interruptible(1000);
554                 tda9887_status(t);
555         }
556 }
557
558 /* ---------------------------------------------------------------------- */
559
560 static void tda9887_tuner_status(struct i2c_client *client)
561 {
562         struct tuner *t = i2c_get_clientdata(client);
563         struct tda9887_priv *priv = t->priv;
564         tda9887_info("Data bytes: b=0x%02x c=0x%02x e=0x%02x\n", priv->data[1], priv->data[2], priv->data[3]);
565 }
566
567 static int tda9887_get_afc(struct i2c_client *client)
568 {
569         struct tuner *t = i2c_get_clientdata(client);
570         static int AFC_BITS_2_kHz[] = {
571                 -12500,  -37500,  -62500,  -97500,
572                 -112500, -137500, -162500, -187500,
573                 187500,  162500,  137500,  112500,
574                 97500 ,  62500,   37500 ,  12500
575         };
576         int afc=0;
577         __u8 reg = 0;
578
579         if (1 == i2c_master_recv(&t->i2c,&reg,1))
580                 afc = AFC_BITS_2_kHz[(reg>>1)&0x0f];
581
582         return afc;
583 }
584
585 static void tda9887_standby(struct i2c_client *client)
586 {
587         tda9887_configure(client);
588 }
589
590 static void tda9887_set_freq(struct i2c_client *client, unsigned int freq)
591 {
592         tda9887_configure(client);
593 }
594
595 static void tda9887_release(struct i2c_client *c)
596 {
597         struct tuner *t = i2c_get_clientdata(c);
598
599         kfree(t->priv);
600         t->priv = NULL;
601 }
602
603 static struct tuner_operations tda9887_tuner_ops = {
604         .set_tv_freq    = tda9887_set_freq,
605         .set_radio_freq = tda9887_set_freq,
606         .standby        = tda9887_standby,
607         .tuner_status   = tda9887_tuner_status,
608         .get_afc        = tda9887_get_afc,
609         .release        = tda9887_release,
610 };
611
612 int tda9887_tuner_init(struct i2c_client *c)
613 {
614         struct tda9887_priv *priv = NULL;
615         struct tuner *t = i2c_get_clientdata(c);
616
617         priv = kzalloc(sizeof(struct tda9887_priv), GFP_KERNEL);
618         if (priv == NULL)
619                 return -ENOMEM;
620         t->priv = priv;
621
622         strlcpy(c->name, "tda9887", sizeof(c->name));
623
624         tda9887_info("tda988[5/6/7] found @ 0x%x (%s)\n", t->i2c.addr,
625                                                 t->i2c.driver->driver.name);
626
627         memcpy(&t->ops, &tda9887_tuner_ops, sizeof(struct tuner_operations));
628
629         return 0;
630 }
631
632 /*
633  * Overrides for Emacs so that we follow Linus's tabbing style.
634  * ---------------------------------------------------------------------------
635  * Local variables:
636  * c-basic-offset: 8
637  * End:
638  */