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