linux/drivers/staging/media/cxd2099/cxd2099.c
<<
>>
Prefs
   1/*
   2 * cxd2099.c: Driver for the CXD2099AR Common Interface Controller
   3 *
   4 * Copyright (C) 2010-2013 Digital Devices GmbH
   5 *
   6 *
   7 * This program is free software; you can redistribute it and/or
   8 * modify it under the terms of the GNU General Public License
   9 * version 2 only, as published by the Free Software Foundation.
  10 *
  11 *
  12 * This program is distributed in the hope that it will be useful,
  13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15 * GNU General Public License for more details.
  16 *
  17 *
  18 * You should have received a copy of the GNU General Public License
  19 * along with this program; if not, write to the Free Software
  20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  21 * 02110-1301, USA
  22 * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
  23 */
  24
  25#include <linux/slab.h>
  26#include <linux/kernel.h>
  27#include <linux/module.h>
  28#include <linux/i2c.h>
  29#include <linux/wait.h>
  30#include <linux/delay.h>
  31#include <linux/mutex.h>
  32#include <linux/io.h>
  33
  34#include "cxd2099.h"
  35
  36static int buffermode;
  37module_param(buffermode, int, 0444);
  38MODULE_PARM_DESC(buffermode, "Enable use of the CXD2099AR buffer mode (default: disabled)");
  39
  40static int read_data(struct dvb_ca_en50221 *ca, int slot, u8 *ebuf, int ecount);
  41
  42struct cxd {
  43        struct dvb_ca_en50221 en;
  44
  45        struct i2c_adapter *i2c;
  46        struct cxd2099_cfg cfg;
  47
  48        u8     regs[0x23];
  49        u8     lastaddress;
  50        u8     clk_reg_f;
  51        u8     clk_reg_b;
  52        int    mode;
  53        int    ready;
  54        int    dr;
  55        int    write_busy;
  56        int    slot_stat;
  57
  58        u8     amem[1024];
  59        int    amem_read;
  60
  61        int    cammode;
  62        struct mutex lock;
  63
  64        u8     rbuf[1028];
  65        u8     wbuf[1028];
  66};
  67
  68static int i2c_write_reg(struct i2c_adapter *adapter, u8 adr,
  69                         u8 reg, u8 data)
  70{
  71        u8 m[2] = {reg, data};
  72        struct i2c_msg msg = {.addr = adr, .flags = 0, .buf = m, .len = 2};
  73
  74        if (i2c_transfer(adapter, &msg, 1) != 1) {
  75                dev_err(&adapter->dev,
  76                        "Failed to write to I2C register %02x@%02x!\n",
  77                        reg, adr);
  78                return -1;
  79        }
  80        return 0;
  81}
  82
  83static int i2c_write(struct i2c_adapter *adapter, u8 adr,
  84                     u8 *data, u16 len)
  85{
  86        struct i2c_msg msg = {.addr = adr, .flags = 0, .buf = data, .len = len};
  87
  88        if (i2c_transfer(adapter, &msg, 1) != 1) {
  89                dev_err(&adapter->dev, "Failed to write to I2C!\n");
  90                return -1;
  91        }
  92        return 0;
  93}
  94
  95static int i2c_read_reg(struct i2c_adapter *adapter, u8 adr,
  96                        u8 reg, u8 *val)
  97{
  98        struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0,
  99                                   .buf = &reg, .len = 1},
 100                                  {.addr = adr, .flags = I2C_M_RD,
 101                                   .buf = val, .len = 1} };
 102
 103        if (i2c_transfer(adapter, msgs, 2) != 2) {
 104                dev_err(&adapter->dev, "error in i2c_read_reg\n");
 105                return -1;
 106        }
 107        return 0;
 108}
 109
 110static int i2c_read(struct i2c_adapter *adapter, u8 adr,
 111                    u8 reg, u8 *data, u16 n)
 112{
 113        struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0,
 114                                   .buf = &reg, .len = 1},
 115                                  {.addr = adr, .flags = I2C_M_RD,
 116                                   .buf = data, .len = n} };
 117
 118        if (i2c_transfer(adapter, msgs, 2) != 2) {
 119                dev_err(&adapter->dev, "error in i2c_read\n");
 120                return -1;
 121        }
 122        return 0;
 123}
 124
 125static int read_block(struct cxd *ci, u8 adr, u8 *data, u16 n)
 126{
 127        int status = 0;
 128
 129        if (ci->lastaddress != adr)
 130                status = i2c_write_reg(ci->i2c, ci->cfg.adr, 0, adr);
 131        if (!status) {
 132                ci->lastaddress = adr;
 133
 134                while (n) {
 135                        int len = n;
 136
 137                        if (ci->cfg.max_i2c && (len > ci->cfg.max_i2c))
 138                                len = ci->cfg.max_i2c;
 139                        status = i2c_read(ci->i2c, ci->cfg.adr, 1, data, len);
 140                        if (status)
 141                                return status;
 142                        data += len;
 143                        n -= len;
 144                }
 145        }
 146        return status;
 147}
 148
 149static int read_reg(struct cxd *ci, u8 reg, u8 *val)
 150{
 151        return read_block(ci, reg, val, 1);
 152}
 153
 154static int read_pccard(struct cxd *ci, u16 address, u8 *data, u8 n)
 155{
 156        int status;
 157        u8 addr[3] = {2, address & 0xff, address >> 8};
 158
 159        status = i2c_write(ci->i2c, ci->cfg.adr, addr, 3);
 160        if (!status)
 161                status = i2c_read(ci->i2c, ci->cfg.adr, 3, data, n);
 162        return status;
 163}
 164
 165static int write_pccard(struct cxd *ci, u16 address, u8 *data, u8 n)
 166{
 167        int status;
 168        u8 addr[3] = {2, address & 0xff, address >> 8};
 169
 170        status = i2c_write(ci->i2c, ci->cfg.adr, addr, 3);
 171        if (!status) {
 172                u8 buf[256] = {3};
 173
 174                memcpy(buf + 1, data, n);
 175                status = i2c_write(ci->i2c, ci->cfg.adr, buf, n + 1);
 176        }
 177        return status;
 178}
 179
 180static int read_io(struct cxd *ci, u16 address, u8 *val)
 181{
 182        int status;
 183        u8 addr[3] = {2, address & 0xff, address >> 8};
 184
 185        status = i2c_write(ci->i2c, ci->cfg.adr, addr, 3);
 186        if (!status)
 187                status = i2c_read(ci->i2c, ci->cfg.adr, 3, val, 1);
 188        return status;
 189}
 190
 191static int write_io(struct cxd *ci, u16 address, u8 val)
 192{
 193        int status;
 194        u8 addr[3] = {2, address & 0xff, address >> 8};
 195        u8 buf[2] = {3, val};
 196
 197        status = i2c_write(ci->i2c, ci->cfg.adr, addr, 3);
 198        if (!status)
 199                status = i2c_write(ci->i2c, ci->cfg.adr, buf, 2);
 200        return status;
 201}
 202
 203static int write_regm(struct cxd *ci, u8 reg, u8 val, u8 mask)
 204{
 205        int status = 0;
 206
 207        if (ci->lastaddress != reg)
 208                status = i2c_write_reg(ci->i2c, ci->cfg.adr, 0, reg);
 209        if (!status && reg >= 6 && reg <= 8 && mask != 0xff)
 210                status = i2c_read_reg(ci->i2c, ci->cfg.adr, 1, &ci->regs[reg]);
 211        ci->lastaddress = reg;
 212        ci->regs[reg] = (ci->regs[reg] & (~mask)) | val;
 213        if (!status)
 214                status = i2c_write_reg(ci->i2c, ci->cfg.adr, 1, ci->regs[reg]);
 215        if (reg == 0x20)
 216                ci->regs[reg] &= 0x7f;
 217        return status;
 218}
 219
 220static int write_reg(struct cxd *ci, u8 reg, u8 val)
 221{
 222        return write_regm(ci, reg, val, 0xff);
 223}
 224
 225static int write_block(struct cxd *ci, u8 adr, u8 *data, u16 n)
 226{
 227        int status = 0;
 228        u8 *buf = ci->wbuf;
 229
 230        if (ci->lastaddress != adr)
 231                status = i2c_write_reg(ci->i2c, ci->cfg.adr, 0, adr);
 232        if (status)
 233                return status;
 234
 235        ci->lastaddress = adr;
 236        buf[0] = 1;
 237        while (n) {
 238                int len = n;
 239
 240                if (ci->cfg.max_i2c && (len + 1 > ci->cfg.max_i2c))
 241                        len = ci->cfg.max_i2c - 1;
 242                memcpy(buf + 1, data, len);
 243                status = i2c_write(ci->i2c, ci->cfg.adr, buf, len + 1);
 244                if (status)
 245                        return status;
 246                n -= len;
 247                data += len;
 248        }
 249        return status;
 250}
 251
 252static void set_mode(struct cxd *ci, int mode)
 253{
 254        if (mode == ci->mode)
 255                return;
 256
 257        switch (mode) {
 258        case 0x00: /* IO mem */
 259                write_regm(ci, 0x06, 0x00, 0x07);
 260                break;
 261        case 0x01: /* ATT mem */
 262                write_regm(ci, 0x06, 0x02, 0x07);
 263                break;
 264        default:
 265                break;
 266        }
 267        ci->mode = mode;
 268}
 269
 270static void cam_mode(struct cxd *ci, int mode)
 271{
 272        u8 dummy;
 273
 274        if (mode == ci->cammode)
 275                return;
 276
 277        switch (mode) {
 278        case 0x00:
 279                write_regm(ci, 0x20, 0x80, 0x80);
 280                break;
 281        case 0x01:
 282                if (!ci->en.read_data)
 283                        return;
 284                ci->write_busy = 0;
 285                dev_info(&ci->i2c->dev, "enable cam buffer mode\n");
 286                write_reg(ci, 0x0d, 0x00);
 287                write_reg(ci, 0x0e, 0x01);
 288                write_regm(ci, 0x08, 0x40, 0x40);
 289                read_reg(ci, 0x12, &dummy);
 290                write_regm(ci, 0x08, 0x80, 0x80);
 291                break;
 292        default:
 293                break;
 294        }
 295        ci->cammode = mode;
 296}
 297
 298static int init(struct cxd *ci)
 299{
 300        int status;
 301
 302        mutex_lock(&ci->lock);
 303        ci->mode = -1;
 304        do {
 305                status = write_reg(ci, 0x00, 0x00);
 306                if (status < 0)
 307                        break;
 308                status = write_reg(ci, 0x01, 0x00);
 309                if (status < 0)
 310                        break;
 311                status = write_reg(ci, 0x02, 0x10);
 312                if (status < 0)
 313                        break;
 314                status = write_reg(ci, 0x03, 0x00);
 315                if (status < 0)
 316                        break;
 317                status = write_reg(ci, 0x05, 0xFF);
 318                if (status < 0)
 319                        break;
 320                status = write_reg(ci, 0x06, 0x1F);
 321                if (status < 0)
 322                        break;
 323                status = write_reg(ci, 0x07, 0x1F);
 324                if (status < 0)
 325                        break;
 326                status = write_reg(ci, 0x08, 0x28);
 327                if (status < 0)
 328                        break;
 329                status = write_reg(ci, 0x14, 0x20);
 330                if (status < 0)
 331                        break;
 332
 333                /* TOSTRT = 8, Mode B (gated clock), falling Edge,
 334                 * Serial, POL=HIGH, MSB
 335                 */
 336                status = write_reg(ci, 0x0A, 0xA7);
 337                if (status < 0)
 338                        break;
 339
 340                status = write_reg(ci, 0x0B, 0x33);
 341                if (status < 0)
 342                        break;
 343                status = write_reg(ci, 0x0C, 0x33);
 344                if (status < 0)
 345                        break;
 346
 347                status = write_regm(ci, 0x14, 0x00, 0x0F);
 348                if (status < 0)
 349                        break;
 350                status = write_reg(ci, 0x15, ci->clk_reg_b);
 351                if (status < 0)
 352                        break;
 353                status = write_regm(ci, 0x16, 0x00, 0x0F);
 354                if (status < 0)
 355                        break;
 356                status = write_reg(ci, 0x17, ci->clk_reg_f);
 357                if (status < 0)
 358                        break;
 359
 360                if (ci->cfg.clock_mode == 2) {
 361                        /* bitrate*2^13/ 72000 */
 362                        u32 reg = ((ci->cfg.bitrate << 13) + 71999) / 72000;
 363
 364                        if (ci->cfg.polarity) {
 365                                status = write_reg(ci, 0x09, 0x6f);
 366                                if (status < 0)
 367                                        break;
 368                        } else {
 369                                status = write_reg(ci, 0x09, 0x6d);
 370                                if (status < 0)
 371                                        break;
 372                        }
 373                        status = write_reg(ci, 0x20, 0x08);
 374                        if (status < 0)
 375                                break;
 376                        status = write_reg(ci, 0x21, (reg >> 8) & 0xff);
 377                        if (status < 0)
 378                                break;
 379                        status = write_reg(ci, 0x22, reg & 0xff);
 380                        if (status < 0)
 381                                break;
 382                } else if (ci->cfg.clock_mode == 1) {
 383                        if (ci->cfg.polarity) {
 384                                status = write_reg(ci, 0x09, 0x6f); /* D */
 385                                if (status < 0)
 386                                        break;
 387                        } else {
 388                                status = write_reg(ci, 0x09, 0x6d);
 389                                if (status < 0)
 390                                        break;
 391                        }
 392                        status = write_reg(ci, 0x20, 0x68);
 393                        if (status < 0)
 394                                break;
 395                        status = write_reg(ci, 0x21, 0x00);
 396                        if (status < 0)
 397                                break;
 398                        status = write_reg(ci, 0x22, 0x02);
 399                        if (status < 0)
 400                                break;
 401                } else {
 402                        if (ci->cfg.polarity) {
 403                                status = write_reg(ci, 0x09, 0x4f); /* C */
 404                                if (status < 0)
 405                                        break;
 406                        } else {
 407                                status = write_reg(ci, 0x09, 0x4d);
 408                                if (status < 0)
 409                                        break;
 410                        }
 411                        status = write_reg(ci, 0x20, 0x28);
 412                        if (status < 0)
 413                                break;
 414                        status = write_reg(ci, 0x21, 0x00);
 415                        if (status < 0)
 416                                break;
 417                        status = write_reg(ci, 0x22, 0x07);
 418                        if (status < 0)
 419                                break;
 420                }
 421
 422                status = write_regm(ci, 0x20, 0x80, 0x80);
 423                if (status < 0)
 424                        break;
 425                status = write_regm(ci, 0x03, 0x02, 0x02);
 426                if (status < 0)
 427                        break;
 428                status = write_reg(ci, 0x01, 0x04);
 429                if (status < 0)
 430                        break;
 431                status = write_reg(ci, 0x00, 0x31);
 432                if (status < 0)
 433                        break;
 434
 435                /* Put TS in bypass */
 436                status = write_regm(ci, 0x09, 0x08, 0x08);
 437                if (status < 0)
 438                        break;
 439                ci->cammode = -1;
 440                cam_mode(ci, 0);
 441        } while (0);
 442        mutex_unlock(&ci->lock);
 443
 444        return 0;
 445}
 446
 447static int read_attribute_mem(struct dvb_ca_en50221 *ca,
 448                              int slot, int address)
 449{
 450        struct cxd *ci = ca->data;
 451        u8 val;
 452
 453        mutex_lock(&ci->lock);
 454        set_mode(ci, 1);
 455        read_pccard(ci, address, &val, 1);
 456        mutex_unlock(&ci->lock);
 457        return val;
 458}
 459
 460static int write_attribute_mem(struct dvb_ca_en50221 *ca, int slot,
 461                               int address, u8 value)
 462{
 463        struct cxd *ci = ca->data;
 464
 465        mutex_lock(&ci->lock);
 466        set_mode(ci, 1);
 467        write_pccard(ci, address, &value, 1);
 468        mutex_unlock(&ci->lock);
 469        return 0;
 470}
 471
 472static int read_cam_control(struct dvb_ca_en50221 *ca,
 473                            int slot, u8 address)
 474{
 475        struct cxd *ci = ca->data;
 476        u8 val;
 477
 478        mutex_lock(&ci->lock);
 479        set_mode(ci, 0);
 480        read_io(ci, address, &val);
 481        mutex_unlock(&ci->lock);
 482        return val;
 483}
 484
 485static int write_cam_control(struct dvb_ca_en50221 *ca, int slot,
 486                             u8 address, u8 value)
 487{
 488        struct cxd *ci = ca->data;
 489
 490        mutex_lock(&ci->lock);
 491        set_mode(ci, 0);
 492        write_io(ci, address, value);
 493        mutex_unlock(&ci->lock);
 494        return 0;
 495}
 496
 497static int slot_reset(struct dvb_ca_en50221 *ca, int slot)
 498{
 499        struct cxd *ci = ca->data;
 500
 501        if (ci->cammode)
 502                read_data(ca, slot, ci->rbuf, 0);
 503
 504        mutex_lock(&ci->lock);
 505        cam_mode(ci, 0);
 506        write_reg(ci, 0x00, 0x21);
 507        write_reg(ci, 0x06, 0x1F);
 508        write_reg(ci, 0x00, 0x31);
 509        write_regm(ci, 0x20, 0x80, 0x80);
 510        write_reg(ci, 0x03, 0x02);
 511        ci->ready = 0;
 512        ci->mode = -1;
 513        {
 514                int i;
 515
 516                for (i = 0; i < 100; i++) {
 517                        usleep_range(10000, 11000);
 518                        if (ci->ready)
 519                                break;
 520                }
 521        }
 522        mutex_unlock(&ci->lock);
 523        return 0;
 524}
 525
 526static int slot_shutdown(struct dvb_ca_en50221 *ca, int slot)
 527{
 528        struct cxd *ci = ca->data;
 529
 530        dev_info(&ci->i2c->dev, "%s\n", __func__);
 531        if (ci->cammode)
 532                read_data(ca, slot, ci->rbuf, 0);
 533        mutex_lock(&ci->lock);
 534        write_reg(ci, 0x00, 0x21);
 535        write_reg(ci, 0x06, 0x1F);
 536        msleep(300);
 537
 538        write_regm(ci, 0x09, 0x08, 0x08);
 539        write_regm(ci, 0x20, 0x80, 0x80); /* Reset CAM Mode */
 540        write_regm(ci, 0x06, 0x07, 0x07); /* Clear IO Mode */
 541
 542        ci->mode = -1;
 543        ci->write_busy = 0;
 544        mutex_unlock(&ci->lock);
 545        return 0;
 546}
 547
 548static int slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
 549{
 550        struct cxd *ci = ca->data;
 551
 552        mutex_lock(&ci->lock);
 553        write_regm(ci, 0x09, 0x00, 0x08);
 554        set_mode(ci, 0);
 555        cam_mode(ci, 1);
 556        mutex_unlock(&ci->lock);
 557        return 0;
 558}
 559
 560static int campoll(struct cxd *ci)
 561{
 562        u8 istat;
 563
 564        read_reg(ci, 0x04, &istat);
 565        if (!istat)
 566                return 0;
 567        write_reg(ci, 0x05, istat);
 568
 569        if (istat & 0x40)
 570                ci->dr = 1;
 571        if (istat & 0x20)
 572                ci->write_busy = 0;
 573
 574        if (istat & 2) {
 575                u8 slotstat;
 576
 577                read_reg(ci, 0x01, &slotstat);
 578                if (!(2 & slotstat)) {
 579                        if (!ci->slot_stat) {
 580                                ci->slot_stat |=
 581                                              DVB_CA_EN50221_POLL_CAM_PRESENT;
 582                                write_regm(ci, 0x03, 0x08, 0x08);
 583                        }
 584
 585                } else {
 586                        if (ci->slot_stat) {
 587                                ci->slot_stat = 0;
 588                                write_regm(ci, 0x03, 0x00, 0x08);
 589                                dev_info(&ci->i2c->dev, "NO CAM\n");
 590                                ci->ready = 0;
 591                        }
 592                }
 593                if ((istat & 8) &&
 594                    (ci->slot_stat == DVB_CA_EN50221_POLL_CAM_PRESENT)) {
 595                        ci->ready = 1;
 596                        ci->slot_stat |= DVB_CA_EN50221_POLL_CAM_READY;
 597                }
 598        }
 599        return 0;
 600}
 601
 602static int poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open)
 603{
 604        struct cxd *ci = ca->data;
 605        u8 slotstat;
 606
 607        mutex_lock(&ci->lock);
 608        campoll(ci);
 609        read_reg(ci, 0x01, &slotstat);
 610        mutex_unlock(&ci->lock);
 611
 612        return ci->slot_stat;
 613}
 614
 615static int read_data(struct dvb_ca_en50221 *ca, int slot, u8 *ebuf, int ecount)
 616{
 617        struct cxd *ci = ca->data;
 618        u8 msb, lsb;
 619        u16 len;
 620
 621        mutex_lock(&ci->lock);
 622        campoll(ci);
 623        mutex_unlock(&ci->lock);
 624
 625        if (!ci->dr)
 626                return 0;
 627
 628        mutex_lock(&ci->lock);
 629        read_reg(ci, 0x0f, &msb);
 630        read_reg(ci, 0x10, &lsb);
 631        len = ((u16)msb << 8) | lsb;
 632        if (len > ecount || len < 2) {
 633                /* read it anyway or cxd may hang */
 634                read_block(ci, 0x12, ci->rbuf, len);
 635                mutex_unlock(&ci->lock);
 636                return -EIO;
 637        }
 638        read_block(ci, 0x12, ebuf, len);
 639        ci->dr = 0;
 640        mutex_unlock(&ci->lock);
 641        return len;
 642}
 643
 644static int write_data(struct dvb_ca_en50221 *ca, int slot, u8 *ebuf, int ecount)
 645{
 646        struct cxd *ci = ca->data;
 647
 648        if (ci->write_busy)
 649                return -EAGAIN;
 650        mutex_lock(&ci->lock);
 651        write_reg(ci, 0x0d, ecount >> 8);
 652        write_reg(ci, 0x0e, ecount & 0xff);
 653        write_block(ci, 0x11, ebuf, ecount);
 654        ci->write_busy = 1;
 655        mutex_unlock(&ci->lock);
 656        return ecount;
 657}
 658
 659static struct dvb_ca_en50221 en_templ = {
 660        .read_attribute_mem  = read_attribute_mem,
 661        .write_attribute_mem = write_attribute_mem,
 662        .read_cam_control    = read_cam_control,
 663        .write_cam_control   = write_cam_control,
 664        .slot_reset          = slot_reset,
 665        .slot_shutdown       = slot_shutdown,
 666        .slot_ts_enable      = slot_ts_enable,
 667        .poll_slot_status    = poll_slot_status,
 668        .read_data           = read_data,
 669        .write_data          = write_data,
 670};
 671
 672struct dvb_ca_en50221 *cxd2099_attach(struct cxd2099_cfg *cfg,
 673                                      void *priv,
 674                                      struct i2c_adapter *i2c)
 675{
 676        struct cxd *ci;
 677        u8 val;
 678
 679        if (i2c_read_reg(i2c, cfg->adr, 0, &val) < 0) {
 680                dev_info(&i2c->dev, "No CXD2099 detected at %02x\n", cfg->adr);
 681                return NULL;
 682        }
 683
 684        ci = kzalloc(sizeof(*ci), GFP_KERNEL);
 685        if (!ci)
 686                return NULL;
 687
 688        mutex_init(&ci->lock);
 689        ci->cfg = *cfg;
 690        ci->i2c = i2c;
 691        ci->lastaddress = 0xff;
 692        ci->clk_reg_b = 0x4a;
 693        ci->clk_reg_f = 0x1b;
 694
 695        ci->en = en_templ;
 696        ci->en.data = ci;
 697        init(ci);
 698        dev_info(&i2c->dev, "Attached CXD2099AR at %02x\n", ci->cfg.adr);
 699
 700        if (!buffermode) {
 701                ci->en.read_data = NULL;
 702                ci->en.write_data = NULL;
 703        } else {
 704                dev_info(&i2c->dev, "Using CXD2099AR buffer mode");
 705        }
 706
 707        return &ci->en;
 708}
 709EXPORT_SYMBOL(cxd2099_attach);
 710
 711MODULE_DESCRIPTION("cxd2099");
 712MODULE_AUTHOR("Ralph Metzler");
 713MODULE_LICENSE("GPL");
 714