tpm: Get rid of chip->pdev
[cascardo/linux.git] / drivers / char / tpm / tpm_infineon.c
1 /*
2  * Description:
3  * Device Driver for the Infineon Technologies
4  * SLD 9630 TT 1.1 and SLB 9635 TT 1.2 Trusted Platform Module
5  * Specifications at www.trustedcomputinggroup.org
6  *
7  * Copyright (C) 2005, Marcel Selhorst <tpmdd@selhorst.net>
8  * Sirrix AG - security technologies <tpmdd@sirrix.com> and
9  * Applied Data Security Group, Ruhr-University Bochum, Germany
10  * Project-Homepage: http://www.trust.rub.de/projects/linux-device-driver-infineon-tpm/ 
11  *
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License as
14  * published by the Free Software Foundation, version 2 of the
15  * License.
16  */
17
18 #include <linux/init.h>
19 #include <linux/pnp.h>
20 #include "tpm.h"
21
22 /* Infineon specific definitions */
23 /* maximum number of WTX-packages */
24 #define TPM_MAX_WTX_PACKAGES    50
25 /* msleep-Time for WTX-packages */
26 #define TPM_WTX_MSLEEP_TIME     20
27 /* msleep-Time --> Interval to check status register */
28 #define TPM_MSLEEP_TIME         3
29 /* gives number of max. msleep()-calls before throwing timeout */
30 #define TPM_MAX_TRIES           5000
31 #define TPM_INFINEON_DEV_VEN_VALUE      0x15D1
32
33 #define TPM_INF_IO_PORT         0x0
34 #define TPM_INF_IO_MEM          0x1
35
36 #define TPM_INF_ADDR            0x0
37 #define TPM_INF_DATA            0x1
38
39 struct tpm_inf_dev {
40         int iotype;
41
42         void __iomem *mem_base; /* MMIO ioremap'd addr */
43         unsigned long map_base; /* phys MMIO base */
44         unsigned long map_size; /* MMIO region size */
45         unsigned int index_off; /* index register offset */
46
47         unsigned int data_regs; /* Data registers */
48         unsigned int data_size;
49
50         unsigned int config_port;       /* IO Port config index reg */
51         unsigned int config_size;
52 };
53
54 static struct tpm_inf_dev tpm_dev;
55
56 static inline void tpm_data_out(unsigned char data, unsigned char offset)
57 {
58         if (tpm_dev.iotype == TPM_INF_IO_PORT)
59                 outb(data, tpm_dev.data_regs + offset);
60         else
61                 writeb(data, tpm_dev.mem_base + tpm_dev.data_regs + offset);
62 }
63
64 static inline unsigned char tpm_data_in(unsigned char offset)
65 {
66         if (tpm_dev.iotype == TPM_INF_IO_PORT)
67                 return inb(tpm_dev.data_regs + offset);
68         else
69                 return readb(tpm_dev.mem_base + tpm_dev.data_regs + offset);
70 }
71
72 static inline void tpm_config_out(unsigned char data, unsigned char offset)
73 {
74         if (tpm_dev.iotype == TPM_INF_IO_PORT)
75                 outb(data, tpm_dev.config_port + offset);
76         else
77                 writeb(data, tpm_dev.mem_base + tpm_dev.index_off + offset);
78 }
79
80 static inline unsigned char tpm_config_in(unsigned char offset)
81 {
82         if (tpm_dev.iotype == TPM_INF_IO_PORT)
83                 return inb(tpm_dev.config_port + offset);
84         else
85                 return readb(tpm_dev.mem_base + tpm_dev.index_off + offset);
86 }
87
88 /* TPM header definitions */
89 enum infineon_tpm_header {
90         TPM_VL_VER = 0x01,
91         TPM_VL_CHANNEL_CONTROL = 0x07,
92         TPM_VL_CHANNEL_PERSONALISATION = 0x0A,
93         TPM_VL_CHANNEL_TPM = 0x0B,
94         TPM_VL_CONTROL = 0x00,
95         TPM_INF_NAK = 0x15,
96         TPM_CTRL_WTX = 0x10,
97         TPM_CTRL_WTX_ABORT = 0x18,
98         TPM_CTRL_WTX_ABORT_ACK = 0x18,
99         TPM_CTRL_ERROR = 0x20,
100         TPM_CTRL_CHAININGACK = 0x40,
101         TPM_CTRL_CHAINING = 0x80,
102         TPM_CTRL_DATA = 0x04,
103         TPM_CTRL_DATA_CHA = 0x84,
104         TPM_CTRL_DATA_CHA_ACK = 0xC4
105 };
106
107 enum infineon_tpm_register {
108         WRFIFO = 0x00,
109         RDFIFO = 0x01,
110         STAT = 0x02,
111         CMD = 0x03
112 };
113
114 enum infineon_tpm_command_bits {
115         CMD_DIS = 0x00,
116         CMD_LP = 0x01,
117         CMD_RES = 0x02,
118         CMD_IRQC = 0x06
119 };
120
121 enum infineon_tpm_status_bits {
122         STAT_XFE = 0x00,
123         STAT_LPA = 0x01,
124         STAT_FOK = 0x02,
125         STAT_TOK = 0x03,
126         STAT_IRQA = 0x06,
127         STAT_RDA = 0x07
128 };
129
130 /* some outgoing values */
131 enum infineon_tpm_values {
132         CHIP_ID1 = 0x20,
133         CHIP_ID2 = 0x21,
134         TPM_DAR = 0x30,
135         RESET_LP_IRQC_DISABLE = 0x41,
136         ENABLE_REGISTER_PAIR = 0x55,
137         IOLIMH = 0x60,
138         IOLIML = 0x61,
139         DISABLE_REGISTER_PAIR = 0xAA,
140         IDVENL = 0xF1,
141         IDVENH = 0xF2,
142         IDPDL = 0xF3,
143         IDPDH = 0xF4
144 };
145
146 static int number_of_wtx;
147
148 static int empty_fifo(struct tpm_chip *chip, int clear_wrfifo)
149 {
150         int status;
151         int check = 0;
152         int i;
153
154         if (clear_wrfifo) {
155                 for (i = 0; i < 4096; i++) {
156                         status = tpm_data_in(WRFIFO);
157                         if (status == 0xff) {
158                                 if (check == 5)
159                                         break;
160                                 else
161                                         check++;
162                         }
163                 }
164         }
165         /* Note: The values which are currently in the FIFO of the TPM
166            are thrown away since there is no usage for them. Usually,
167            this has nothing to say, since the TPM will give its answer
168            immediately or will be aborted anyway, so the data here is
169            usually garbage and useless.
170            We have to clean this, because the next communication with
171            the TPM would be rubbish, if there is still some old data
172            in the Read FIFO.
173          */
174         i = 0;
175         do {
176                 status = tpm_data_in(RDFIFO);
177                 status = tpm_data_in(STAT);
178                 i++;
179                 if (i == TPM_MAX_TRIES)
180                         return -EIO;
181         } while ((status & (1 << STAT_RDA)) != 0);
182         return 0;
183 }
184
185 static int wait(struct tpm_chip *chip, int wait_for_bit)
186 {
187         int status;
188         int i;
189         for (i = 0; i < TPM_MAX_TRIES; i++) {
190                 status = tpm_data_in(STAT);
191                 /* check the status-register if wait_for_bit is set */
192                 if (status & 1 << wait_for_bit)
193                         break;
194                 msleep(TPM_MSLEEP_TIME);
195         }
196         if (i == TPM_MAX_TRIES) {       /* timeout occurs */
197                 if (wait_for_bit == STAT_XFE)
198                         dev_err(&chip->dev, "Timeout in wait(STAT_XFE)\n");
199                 if (wait_for_bit == STAT_RDA)
200                         dev_err(&chip->dev, "Timeout in wait(STAT_RDA)\n");
201                 return -EIO;
202         }
203         return 0;
204 };
205
206 static void wait_and_send(struct tpm_chip *chip, u8 sendbyte)
207 {
208         wait(chip, STAT_XFE);
209         tpm_data_out(sendbyte, WRFIFO);
210 }
211
212     /* Note: WTX means Waiting-Time-Extension. Whenever the TPM needs more
213        calculation time, it sends a WTX-package, which has to be acknowledged
214        or aborted. This usually occurs if you are hammering the TPM with key
215        creation. Set the maximum number of WTX-packages in the definitions
216        above, if the number is reached, the waiting-time will be denied
217        and the TPM command has to be resend.
218      */
219
220 static void tpm_wtx(struct tpm_chip *chip)
221 {
222         number_of_wtx++;
223         dev_info(&chip->dev, "Granting WTX (%02d / %02d)\n",
224                  number_of_wtx, TPM_MAX_WTX_PACKAGES);
225         wait_and_send(chip, TPM_VL_VER);
226         wait_and_send(chip, TPM_CTRL_WTX);
227         wait_and_send(chip, 0x00);
228         wait_and_send(chip, 0x00);
229         msleep(TPM_WTX_MSLEEP_TIME);
230 }
231
232 static void tpm_wtx_abort(struct tpm_chip *chip)
233 {
234         dev_info(&chip->dev, "Aborting WTX\n");
235         wait_and_send(chip, TPM_VL_VER);
236         wait_and_send(chip, TPM_CTRL_WTX_ABORT);
237         wait_and_send(chip, 0x00);
238         wait_and_send(chip, 0x00);
239         number_of_wtx = 0;
240         msleep(TPM_WTX_MSLEEP_TIME);
241 }
242
243 static int tpm_inf_recv(struct tpm_chip *chip, u8 * buf, size_t count)
244 {
245         int i;
246         int ret;
247         u32 size = 0;
248         number_of_wtx = 0;
249
250 recv_begin:
251         /* start receiving header */
252         for (i = 0; i < 4; i++) {
253                 ret = wait(chip, STAT_RDA);
254                 if (ret)
255                         return -EIO;
256                 buf[i] = tpm_data_in(RDFIFO);
257         }
258
259         if (buf[0] != TPM_VL_VER) {
260                 dev_err(&chip->dev,
261                         "Wrong transport protocol implementation!\n");
262                 return -EIO;
263         }
264
265         if (buf[1] == TPM_CTRL_DATA) {
266                 /* size of the data received */
267                 size = ((buf[2] << 8) | buf[3]);
268
269                 for (i = 0; i < size; i++) {
270                         wait(chip, STAT_RDA);
271                         buf[i] = tpm_data_in(RDFIFO);
272                 }
273
274                 if ((size == 0x6D00) && (buf[1] == 0x80)) {
275                         dev_err(&chip->dev, "Error handling on vendor layer!\n");
276                         return -EIO;
277                 }
278
279                 for (i = 0; i < size; i++)
280                         buf[i] = buf[i + 6];
281
282                 size = size - 6;
283                 return size;
284         }
285
286         if (buf[1] == TPM_CTRL_WTX) {
287                 dev_info(&chip->dev, "WTX-package received\n");
288                 if (number_of_wtx < TPM_MAX_WTX_PACKAGES) {
289                         tpm_wtx(chip);
290                         goto recv_begin;
291                 } else {
292                         tpm_wtx_abort(chip);
293                         goto recv_begin;
294                 }
295         }
296
297         if (buf[1] == TPM_CTRL_WTX_ABORT_ACK) {
298                 dev_info(&chip->dev, "WTX-abort acknowledged\n");
299                 return size;
300         }
301
302         if (buf[1] == TPM_CTRL_ERROR) {
303                 dev_err(&chip->dev, "ERROR-package received:\n");
304                 if (buf[4] == TPM_INF_NAK)
305                         dev_err(&chip->dev,
306                                 "-> Negative acknowledgement"
307                                 " - retransmit command!\n");
308                 return -EIO;
309         }
310         return -EIO;
311 }
312
313 static int tpm_inf_send(struct tpm_chip *chip, u8 * buf, size_t count)
314 {
315         int i;
316         int ret;
317         u8 count_high, count_low, count_4, count_3, count_2, count_1;
318
319         /* Disabling Reset, LP and IRQC */
320         tpm_data_out(RESET_LP_IRQC_DISABLE, CMD);
321
322         ret = empty_fifo(chip, 1);
323         if (ret) {
324                 dev_err(&chip->dev, "Timeout while clearing FIFO\n");
325                 return -EIO;
326         }
327
328         ret = wait(chip, STAT_XFE);
329         if (ret)
330                 return -EIO;
331
332         count_4 = (count & 0xff000000) >> 24;
333         count_3 = (count & 0x00ff0000) >> 16;
334         count_2 = (count & 0x0000ff00) >> 8;
335         count_1 = (count & 0x000000ff);
336         count_high = ((count + 6) & 0xffffff00) >> 8;
337         count_low = ((count + 6) & 0x000000ff);
338
339         /* Sending Header */
340         wait_and_send(chip, TPM_VL_VER);
341         wait_and_send(chip, TPM_CTRL_DATA);
342         wait_and_send(chip, count_high);
343         wait_and_send(chip, count_low);
344
345         /* Sending Data Header */
346         wait_and_send(chip, TPM_VL_VER);
347         wait_and_send(chip, TPM_VL_CHANNEL_TPM);
348         wait_and_send(chip, count_4);
349         wait_and_send(chip, count_3);
350         wait_and_send(chip, count_2);
351         wait_and_send(chip, count_1);
352
353         /* Sending Data */
354         for (i = 0; i < count; i++) {
355                 wait_and_send(chip, buf[i]);
356         }
357         return count;
358 }
359
360 static void tpm_inf_cancel(struct tpm_chip *chip)
361 {
362         /*
363            Since we are using the legacy mode to communicate
364            with the TPM, we have no cancel functions, but have
365            a workaround for interrupting the TPM through WTX.
366          */
367 }
368
369 static u8 tpm_inf_status(struct tpm_chip *chip)
370 {
371         return tpm_data_in(STAT);
372 }
373
374 static const struct tpm_class_ops tpm_inf = {
375         .recv = tpm_inf_recv,
376         .send = tpm_inf_send,
377         .cancel = tpm_inf_cancel,
378         .status = tpm_inf_status,
379         .req_complete_mask = 0,
380         .req_complete_val = 0,
381 };
382
383 static const struct pnp_device_id tpm_inf_pnp_tbl[] = {
384         /* Infineon TPMs */
385         {"IFX0101", 0},
386         {"IFX0102", 0},
387         {"", 0}
388 };
389
390 MODULE_DEVICE_TABLE(pnp, tpm_inf_pnp_tbl);
391
392 static int tpm_inf_pnp_probe(struct pnp_dev *dev,
393                                        const struct pnp_device_id *dev_id)
394 {
395         int rc = 0;
396         u8 iol, ioh;
397         int vendorid[2];
398         int version[2];
399         int productid[2];
400         char chipname[20];
401         struct tpm_chip *chip;
402
403         /* read IO-ports through PnP */
404         if (pnp_port_valid(dev, 0) && pnp_port_valid(dev, 1) &&
405             !(pnp_port_flags(dev, 0) & IORESOURCE_DISABLED)) {
406
407                 tpm_dev.iotype = TPM_INF_IO_PORT;
408
409                 tpm_dev.config_port = pnp_port_start(dev, 0);
410                 tpm_dev.config_size = pnp_port_len(dev, 0);
411                 tpm_dev.data_regs = pnp_port_start(dev, 1);
412                 tpm_dev.data_size = pnp_port_len(dev, 1);
413                 if ((tpm_dev.data_size < 4) || (tpm_dev.config_size < 2)) {
414                         rc = -EINVAL;
415                         goto err_last;
416                 }
417                 dev_info(&dev->dev, "Found %s with ID %s\n",
418                          dev->name, dev_id->id);
419                 if (!((tpm_dev.data_regs >> 8) & 0xff)) {
420                         rc = -EINVAL;
421                         goto err_last;
422                 }
423                 /* publish my base address and request region */
424                 if (request_region(tpm_dev.data_regs, tpm_dev.data_size,
425                                    "tpm_infineon0") == NULL) {
426                         rc = -EINVAL;
427                         goto err_last;
428                 }
429                 if (request_region(tpm_dev.config_port, tpm_dev.config_size,
430                                    "tpm_infineon0") == NULL) {
431                         release_region(tpm_dev.data_regs, tpm_dev.data_size);
432                         rc = -EINVAL;
433                         goto err_last;
434                 }
435         } else if (pnp_mem_valid(dev, 0) &&
436                    !(pnp_mem_flags(dev, 0) & IORESOURCE_DISABLED)) {
437
438                 tpm_dev.iotype = TPM_INF_IO_MEM;
439
440                 tpm_dev.map_base = pnp_mem_start(dev, 0);
441                 tpm_dev.map_size = pnp_mem_len(dev, 0);
442
443                 dev_info(&dev->dev, "Found %s with ID %s\n",
444                          dev->name, dev_id->id);
445
446                 /* publish my base address and request region */
447                 if (request_mem_region(tpm_dev.map_base, tpm_dev.map_size,
448                                        "tpm_infineon0") == NULL) {
449                         rc = -EINVAL;
450                         goto err_last;
451                 }
452
453                 tpm_dev.mem_base = ioremap(tpm_dev.map_base, tpm_dev.map_size);
454                 if (tpm_dev.mem_base == NULL) {
455                         release_mem_region(tpm_dev.map_base, tpm_dev.map_size);
456                         rc = -EINVAL;
457                         goto err_last;
458                 }
459
460                 /*
461                  * The only known MMIO based Infineon TPM system provides
462                  * a single large mem region with the device config
463                  * registers at the default TPM_ADDR.  The data registers
464                  * seem like they could be placed anywhere within the MMIO
465                  * region, but lets just put them at zero offset.
466                  */
467                 tpm_dev.index_off = TPM_ADDR;
468                 tpm_dev.data_regs = 0x0;
469         } else {
470                 rc = -EINVAL;
471                 goto err_last;
472         }
473
474         /* query chip for its vendor, its version number a.s.o. */
475         tpm_config_out(ENABLE_REGISTER_PAIR, TPM_INF_ADDR);
476         tpm_config_out(IDVENL, TPM_INF_ADDR);
477         vendorid[1] = tpm_config_in(TPM_INF_DATA);
478         tpm_config_out(IDVENH, TPM_INF_ADDR);
479         vendorid[0] = tpm_config_in(TPM_INF_DATA);
480         tpm_config_out(IDPDL, TPM_INF_ADDR);
481         productid[1] = tpm_config_in(TPM_INF_DATA);
482         tpm_config_out(IDPDH, TPM_INF_ADDR);
483         productid[0] = tpm_config_in(TPM_INF_DATA);
484         tpm_config_out(CHIP_ID1, TPM_INF_ADDR);
485         version[1] = tpm_config_in(TPM_INF_DATA);
486         tpm_config_out(CHIP_ID2, TPM_INF_ADDR);
487         version[0] = tpm_config_in(TPM_INF_DATA);
488
489         switch ((productid[0] << 8) | productid[1]) {
490         case 6:
491                 snprintf(chipname, sizeof(chipname), " (SLD 9630 TT 1.1)");
492                 break;
493         case 11:
494                 snprintf(chipname, sizeof(chipname), " (SLB 9635 TT 1.2)");
495                 break;
496         default:
497                 snprintf(chipname, sizeof(chipname), " (unknown chip)");
498                 break;
499         }
500
501         if ((vendorid[0] << 8 | vendorid[1]) == (TPM_INFINEON_DEV_VEN_VALUE)) {
502
503                 /* configure TPM with IO-ports */
504                 tpm_config_out(IOLIMH, TPM_INF_ADDR);
505                 tpm_config_out((tpm_dev.data_regs >> 8) & 0xff, TPM_INF_DATA);
506                 tpm_config_out(IOLIML, TPM_INF_ADDR);
507                 tpm_config_out((tpm_dev.data_regs & 0xff), TPM_INF_DATA);
508
509                 /* control if IO-ports are set correctly */
510                 tpm_config_out(IOLIMH, TPM_INF_ADDR);
511                 ioh = tpm_config_in(TPM_INF_DATA);
512                 tpm_config_out(IOLIML, TPM_INF_ADDR);
513                 iol = tpm_config_in(TPM_INF_DATA);
514
515                 if ((ioh << 8 | iol) != tpm_dev.data_regs) {
516                         dev_err(&dev->dev,
517                                 "Could not set IO-data registers to 0x%x\n",
518                                 tpm_dev.data_regs);
519                         rc = -EIO;
520                         goto err_release_region;
521                 }
522
523                 /* activate register */
524                 tpm_config_out(TPM_DAR, TPM_INF_ADDR);
525                 tpm_config_out(0x01, TPM_INF_DATA);
526                 tpm_config_out(DISABLE_REGISTER_PAIR, TPM_INF_ADDR);
527
528                 /* disable RESET, LP and IRQC */
529                 tpm_data_out(RESET_LP_IRQC_DISABLE, CMD);
530
531                 /* Finally, we're done, print some infos */
532                 dev_info(&dev->dev, "TPM found: "
533                          "config base 0x%lx, "
534                          "data base 0x%lx, "
535                          "chip version 0x%02x%02x, "
536                          "vendor id 0x%x%x (Infineon), "
537                          "product id 0x%02x%02x"
538                          "%s\n",
539                          tpm_dev.iotype == TPM_INF_IO_PORT ?
540                          tpm_dev.config_port :
541                          tpm_dev.map_base + tpm_dev.index_off,
542                          tpm_dev.iotype == TPM_INF_IO_PORT ?
543                          tpm_dev.data_regs :
544                          tpm_dev.map_base + tpm_dev.data_regs,
545                          version[0], version[1],
546                          vendorid[0], vendorid[1],
547                          productid[0], productid[1], chipname);
548
549                 chip = tpmm_chip_alloc(&dev->dev, &tpm_inf);
550                 if (IS_ERR(chip)) {
551                         rc = PTR_ERR(chip);
552                         goto err_release_region;
553                 }
554
555                 rc = tpm_chip_register(chip);
556                 if (rc)
557                         goto err_release_region;
558
559                 return 0;
560         } else {
561                 rc = -ENODEV;
562                 goto err_release_region;
563         }
564
565 err_release_region:
566         if (tpm_dev.iotype == TPM_INF_IO_PORT) {
567                 release_region(tpm_dev.data_regs, tpm_dev.data_size);
568                 release_region(tpm_dev.config_port, tpm_dev.config_size);
569         } else {
570                 iounmap(tpm_dev.mem_base);
571                 release_mem_region(tpm_dev.map_base, tpm_dev.map_size);
572         }
573
574 err_last:
575         return rc;
576 }
577
578 static void tpm_inf_pnp_remove(struct pnp_dev *dev)
579 {
580         struct tpm_chip *chip = pnp_get_drvdata(dev);
581
582         tpm_chip_unregister(chip);
583
584         if (tpm_dev.iotype == TPM_INF_IO_PORT) {
585                 release_region(tpm_dev.data_regs, tpm_dev.data_size);
586                 release_region(tpm_dev.config_port,
587                                tpm_dev.config_size);
588         } else {
589                 iounmap(tpm_dev.mem_base);
590                 release_mem_region(tpm_dev.map_base, tpm_dev.map_size);
591         }
592 }
593
594 #ifdef CONFIG_PM_SLEEP
595 static int tpm_inf_resume(struct device *dev)
596 {
597         /* Re-configure TPM after suspending */
598         tpm_config_out(ENABLE_REGISTER_PAIR, TPM_INF_ADDR);
599         tpm_config_out(IOLIMH, TPM_INF_ADDR);
600         tpm_config_out((tpm_dev.data_regs >> 8) & 0xff, TPM_INF_DATA);
601         tpm_config_out(IOLIML, TPM_INF_ADDR);
602         tpm_config_out((tpm_dev.data_regs & 0xff), TPM_INF_DATA);
603         /* activate register */
604         tpm_config_out(TPM_DAR, TPM_INF_ADDR);
605         tpm_config_out(0x01, TPM_INF_DATA);
606         tpm_config_out(DISABLE_REGISTER_PAIR, TPM_INF_ADDR);
607         /* disable RESET, LP and IRQC */
608         tpm_data_out(RESET_LP_IRQC_DISABLE, CMD);
609         return tpm_pm_resume(dev);
610 }
611 #endif
612 static SIMPLE_DEV_PM_OPS(tpm_inf_pm, tpm_pm_suspend, tpm_inf_resume);
613
614 static struct pnp_driver tpm_inf_pnp_driver = {
615         .name = "tpm_inf_pnp",
616         .id_table = tpm_inf_pnp_tbl,
617         .probe = tpm_inf_pnp_probe,
618         .remove = tpm_inf_pnp_remove,
619         .driver = {
620                 .pm = &tpm_inf_pm,
621         }
622 };
623
624 module_pnp_driver(tpm_inf_pnp_driver);
625
626 MODULE_AUTHOR("Marcel Selhorst <tpmdd@sirrix.com>");
627 MODULE_DESCRIPTION("Driver for Infineon TPM SLD 9630 TT 1.1 / SLB 9635 TT 1.2");
628 MODULE_VERSION("1.9.2");
629 MODULE_LICENSE("GPL");