0001
0002
0003
0004
0005
0006
0007
0008 #include "au0828.h"
0009 #include "au8522.h"
0010
0011 #include <linux/module.h>
0012 #include <linux/slab.h>
0013 #include <linux/videodev2.h>
0014 #include <media/v4l2-common.h>
0015 #include <linux/mutex.h>
0016
0017
0018 #include <media/tuner.h>
0019
0020
0021
0022
0023
0024
0025
0026
0027 int au0828_debug;
0028 module_param_named(debug, au0828_debug, int, 0644);
0029 MODULE_PARM_DESC(debug,
0030 "set debug bitmask: 1=general, 2=USB, 4=I2C, 8=bridge, 16=IR");
0031
0032 static unsigned int disable_usb_speed_check;
0033 module_param(disable_usb_speed_check, int, 0444);
0034 MODULE_PARM_DESC(disable_usb_speed_check,
0035 "override min bandwidth requirement of 480M bps");
0036
0037 #define _AU0828_BULKPIPE 0x03
0038 #define _BULKPIPESIZE 0xffff
0039
0040 static int send_control_msg(struct au0828_dev *dev, u16 request, u32 value,
0041 u16 index);
0042 static int recv_control_msg(struct au0828_dev *dev, u16 request, u32 value,
0043 u16 index, unsigned char *cp, u16 size);
0044
0045
0046 #define CMD_REQUEST_IN 0x00
0047 #define CMD_REQUEST_OUT 0x01
0048
0049 u32 au0828_readreg(struct au0828_dev *dev, u16 reg)
0050 {
0051 u8 result = 0;
0052
0053 recv_control_msg(dev, CMD_REQUEST_IN, 0, reg, &result, 1);
0054 dprintk(8, "%s(0x%04x) = 0x%02x\n", __func__, reg, result);
0055
0056 return result;
0057 }
0058
0059 u32 au0828_writereg(struct au0828_dev *dev, u16 reg, u32 val)
0060 {
0061 dprintk(8, "%s(0x%04x, 0x%02x)\n", __func__, reg, val);
0062 return send_control_msg(dev, CMD_REQUEST_OUT, val, reg);
0063 }
0064
0065 static int send_control_msg(struct au0828_dev *dev, u16 request, u32 value,
0066 u16 index)
0067 {
0068 int status = -ENODEV;
0069
0070 if (dev->usbdev) {
0071
0072
0073 status = usb_control_msg(dev->usbdev,
0074 usb_sndctrlpipe(dev->usbdev, 0),
0075 request,
0076 USB_DIR_OUT | USB_TYPE_VENDOR |
0077 USB_RECIP_DEVICE,
0078 value, index, NULL, 0, 1000);
0079
0080 status = min(status, 0);
0081
0082 if (status < 0) {
0083 pr_err("%s() Failed sending control message, error %d.\n",
0084 __func__, status);
0085 }
0086
0087 }
0088
0089 return status;
0090 }
0091
0092 static int recv_control_msg(struct au0828_dev *dev, u16 request, u32 value,
0093 u16 index, unsigned char *cp, u16 size)
0094 {
0095 int status = -ENODEV;
0096 mutex_lock(&dev->mutex);
0097 if (dev->usbdev) {
0098 status = usb_control_msg(dev->usbdev,
0099 usb_rcvctrlpipe(dev->usbdev, 0),
0100 request,
0101 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
0102 value, index,
0103 dev->ctrlmsg, size, 1000);
0104
0105 status = min(status, 0);
0106
0107 if (status < 0) {
0108 pr_err("%s() Failed receiving control message, error %d.\n",
0109 __func__, status);
0110 }
0111
0112
0113
0114 memcpy(cp, dev->ctrlmsg, size);
0115 }
0116 mutex_unlock(&dev->mutex);
0117 return status;
0118 }
0119
0120 #ifdef CONFIG_MEDIA_CONTROLLER
0121 static void au0828_media_graph_notify(struct media_entity *new,
0122 void *notify_data);
0123 #endif
0124
0125 static void au0828_unregister_media_device(struct au0828_dev *dev)
0126 {
0127 #ifdef CONFIG_MEDIA_CONTROLLER
0128 struct media_device *mdev = dev->media_dev;
0129 struct media_entity_notify *notify, *nextp;
0130
0131 if (!mdev || !media_devnode_is_registered(mdev->devnode))
0132 return;
0133
0134
0135 list_for_each_entry_safe(notify, nextp, &mdev->entity_notify, list) {
0136 if (notify->notify != au0828_media_graph_notify)
0137 continue;
0138 media_device_unregister_entity_notify(mdev, notify);
0139 }
0140
0141
0142 mutex_lock(&mdev->graph_mutex);
0143 dev->media_dev->source_priv = NULL;
0144 dev->media_dev->enable_source = NULL;
0145 dev->media_dev->disable_source = NULL;
0146 mutex_unlock(&mdev->graph_mutex);
0147
0148 media_device_delete(dev->media_dev, KBUILD_MODNAME, THIS_MODULE);
0149 dev->media_dev = NULL;
0150 #endif
0151 }
0152
0153 void au0828_usb_release(struct au0828_dev *dev)
0154 {
0155 au0828_unregister_media_device(dev);
0156
0157
0158 au0828_i2c_unregister(dev);
0159
0160 kfree(dev);
0161 }
0162
0163 static void au0828_usb_disconnect(struct usb_interface *interface)
0164 {
0165 struct au0828_dev *dev = usb_get_intfdata(interface);
0166
0167 dprintk(1, "%s()\n", __func__);
0168
0169
0170
0171
0172
0173
0174
0175 set_bit(DEV_DISCONNECTED, &dev->dev_state);
0176
0177 au0828_rc_unregister(dev);
0178
0179 au0828_dvb_unregister(dev);
0180
0181 usb_set_intfdata(interface, NULL);
0182 mutex_lock(&dev->mutex);
0183 dev->usbdev = NULL;
0184 mutex_unlock(&dev->mutex);
0185 if (au0828_analog_unregister(dev)) {
0186
0187
0188
0189
0190 return;
0191 }
0192 au0828_usb_release(dev);
0193 }
0194
0195 static int au0828_media_device_init(struct au0828_dev *dev,
0196 struct usb_device *udev)
0197 {
0198 #ifdef CONFIG_MEDIA_CONTROLLER
0199 struct media_device *mdev;
0200
0201 mdev = media_device_usb_allocate(udev, KBUILD_MODNAME, THIS_MODULE);
0202 if (IS_ERR(mdev))
0203 return PTR_ERR(mdev);
0204
0205 dev->media_dev = mdev;
0206 #endif
0207 return 0;
0208 }
0209
0210 #ifdef CONFIG_MEDIA_CONTROLLER
0211 static void au0828_media_graph_notify(struct media_entity *new,
0212 void *notify_data)
0213 {
0214 struct au0828_dev *dev = (struct au0828_dev *) notify_data;
0215 int ret;
0216 struct media_entity *entity, *mixer = NULL, *decoder = NULL;
0217
0218 if (!new) {
0219
0220
0221
0222
0223
0224 media_device_for_each_entity(entity, dev->media_dev) {
0225 if (entity->function == MEDIA_ENT_F_AUDIO_MIXER)
0226 mixer = entity;
0227 else if (entity->function == MEDIA_ENT_F_ATV_DECODER)
0228 decoder = entity;
0229 }
0230 goto create_link;
0231 }
0232
0233 switch (new->function) {
0234 case MEDIA_ENT_F_AUDIO_MIXER:
0235 mixer = new;
0236 if (dev->decoder)
0237 decoder = dev->decoder;
0238 break;
0239 case MEDIA_ENT_F_ATV_DECODER:
0240
0241 media_device_for_each_entity(entity, dev->media_dev) {
0242 if (entity->function == MEDIA_ENT_F_AUDIO_MIXER)
0243 mixer = entity;
0244 }
0245 decoder = new;
0246 break;
0247 default:
0248 break;
0249 }
0250
0251 create_link:
0252 if (decoder && mixer) {
0253 ret = media_get_pad_index(decoder, false,
0254 PAD_SIGNAL_AUDIO);
0255 if (ret >= 0)
0256 ret = media_create_pad_link(decoder, ret,
0257 mixer, 0,
0258 MEDIA_LNK_FL_ENABLED);
0259 if (ret < 0)
0260 dev_err(&dev->usbdev->dev,
0261 "Mixer Pad Link Create Error: %d\n", ret);
0262 }
0263 }
0264
0265 static bool au0828_is_link_shareable(struct media_entity *owner,
0266 struct media_entity *entity)
0267 {
0268 bool shareable = false;
0269
0270
0271 switch (owner->function) {
0272 case MEDIA_ENT_F_IO_V4L:
0273 case MEDIA_ENT_F_AUDIO_CAPTURE:
0274 case MEDIA_ENT_F_IO_VBI:
0275 if (entity->function == MEDIA_ENT_F_IO_V4L ||
0276 entity->function == MEDIA_ENT_F_AUDIO_CAPTURE ||
0277 entity->function == MEDIA_ENT_F_IO_VBI)
0278 shareable = true;
0279 break;
0280 case MEDIA_ENT_F_DTV_DEMOD:
0281 default:
0282 break;
0283 }
0284 return shareable;
0285 }
0286
0287
0288 static int au0828_enable_source(struct media_entity *entity,
0289 struct media_pipeline *pipe)
0290 {
0291 struct media_entity *source, *find_source;
0292 struct media_entity *sink;
0293 struct media_link *link, *found_link = NULL;
0294 int ret = 0;
0295 struct media_device *mdev = entity->graph_obj.mdev;
0296 struct au0828_dev *dev;
0297
0298 if (!mdev)
0299 return -ENODEV;
0300
0301 dev = mdev->source_priv;
0302
0303
0304
0305
0306
0307
0308
0309
0310
0311
0312
0313
0314 if (entity->function == MEDIA_ENT_F_DTV_DEMOD) {
0315 sink = entity;
0316 find_source = dev->tuner;
0317 } else {
0318
0319 if (!dev->decoder) {
0320 ret = -ENODEV;
0321 goto end;
0322 }
0323
0324 sink = dev->decoder;
0325
0326
0327
0328
0329
0330
0331
0332
0333
0334
0335
0336
0337
0338
0339
0340
0341
0342
0343 if (dev->input_type == AU0828_VMUX_TELEVISION)
0344 find_source = dev->tuner;
0345 else if (dev->input_type == AU0828_VMUX_SVIDEO ||
0346 dev->input_type == AU0828_VMUX_COMPOSITE)
0347 find_source = &dev->input_ent[dev->input_type];
0348 else {
0349
0350 ret = 0;
0351 goto end;
0352 }
0353 }
0354
0355
0356 if (dev->active_link) {
0357 if (dev->active_link_owner == entity) {
0358
0359
0360
0361
0362 pr_debug("%s already owns the tuner\n", entity->name);
0363 ret = 0;
0364 goto end;
0365 } else if (au0828_is_link_shareable(dev->active_link_owner,
0366 entity)) {
0367
0368
0369
0370
0371
0372
0373
0374
0375 dev->active_link_shared = true;
0376
0377 dev->active_link_user = entity;
0378 dev->active_link_user_pipe = pipe;
0379 pr_debug("%s owns the tuner %s can share!\n",
0380 dev->active_link_owner->name,
0381 entity->name);
0382 ret = 0;
0383 goto end;
0384 } else {
0385 ret = -EBUSY;
0386 goto end;
0387 }
0388 }
0389
0390 list_for_each_entry(link, &sink->links, list) {
0391
0392 if (link->sink->entity == sink &&
0393 link->source->entity == find_source) {
0394 found_link = link;
0395 break;
0396 }
0397 }
0398
0399 if (!found_link) {
0400 ret = -ENODEV;
0401 goto end;
0402 }
0403
0404
0405 source = found_link->source->entity;
0406 ret = __media_entity_setup_link(found_link, MEDIA_LNK_FL_ENABLED);
0407 if (ret) {
0408 pr_err("Activate link from %s->%s. Error %d\n",
0409 source->name, sink->name, ret);
0410 goto end;
0411 }
0412
0413 ret = __media_pipeline_start(entity, pipe);
0414 if (ret) {
0415 pr_err("Start Pipeline: %s->%s Error %d\n",
0416 source->name, entity->name, ret);
0417 ret = __media_entity_setup_link(found_link, 0);
0418 if (ret)
0419 pr_err("Deactivate link Error %d\n", ret);
0420 goto end;
0421 }
0422
0423
0424
0425
0426
0427 dev->active_link = found_link;
0428 dev->active_link_owner = entity;
0429 dev->active_source = source;
0430 dev->active_sink = sink;
0431
0432 pr_info("Enabled Source: %s->%s->%s Ret %d\n",
0433 dev->active_source->name, dev->active_sink->name,
0434 dev->active_link_owner->name, ret);
0435 end:
0436 pr_debug("%s end: ent:%s fnc:%d ret %d\n",
0437 __func__, entity->name, entity->function, ret);
0438 return ret;
0439 }
0440
0441
0442 static void au0828_disable_source(struct media_entity *entity)
0443 {
0444 int ret = 0;
0445 struct media_device *mdev = entity->graph_obj.mdev;
0446 struct au0828_dev *dev;
0447
0448 if (!mdev)
0449 return;
0450
0451 dev = mdev->source_priv;
0452
0453 if (!dev->active_link)
0454 return;
0455
0456
0457
0458
0459
0460
0461 if (dev->active_link->sink->entity == dev->active_sink &&
0462 dev->active_link->source->entity == dev->active_source) {
0463
0464
0465
0466
0467
0468
0469 bool owner_is_audio = false;
0470
0471 if (dev->active_link_owner->function ==
0472 MEDIA_ENT_F_AUDIO_CAPTURE)
0473 owner_is_audio = true;
0474
0475 if (dev->active_link_shared) {
0476 pr_debug("Shared link owner %s user %s %d\n",
0477 dev->active_link_owner->name,
0478 entity->name, dev->users);
0479
0480
0481
0482
0483
0484
0485
0486
0487
0488 if (dev->active_link_owner != entity) {
0489
0490 if (owner_is_audio && dev->users > 1)
0491 return;
0492
0493 dev->active_link_user = NULL;
0494 dev->active_link_user_pipe = NULL;
0495 dev->active_link_shared = false;
0496 return;
0497 }
0498
0499
0500 if (!owner_is_audio && dev->users > 1)
0501 return;
0502
0503
0504 __media_pipeline_stop(dev->active_link_owner);
0505 pr_debug("Pipeline stop for %s\n",
0506 dev->active_link_owner->name);
0507
0508 ret = __media_pipeline_start(
0509 dev->active_link_user,
0510 dev->active_link_user_pipe);
0511 if (ret) {
0512 pr_err("Start Pipeline: %s->%s %d\n",
0513 dev->active_source->name,
0514 dev->active_link_user->name,
0515 ret);
0516 goto deactivate_link;
0517 }
0518
0519 dev->active_link_owner = dev->active_link_user;
0520 dev->active_link_user = NULL;
0521 dev->active_link_user_pipe = NULL;
0522 dev->active_link_shared = false;
0523
0524 pr_debug("Pipeline started for %s\n",
0525 dev->active_link_owner->name);
0526 return;
0527 } else if (!owner_is_audio && dev->users > 1)
0528
0529 return;
0530
0531 if (dev->active_link_owner != entity)
0532 return;
0533
0534
0535 __media_pipeline_stop(dev->active_link_owner);
0536 pr_debug("Pipeline stop for %s\n",
0537 dev->active_link_owner->name);
0538
0539 deactivate_link:
0540 ret = __media_entity_setup_link(dev->active_link, 0);
0541 if (ret)
0542 pr_err("Deactivate link Error %d\n", ret);
0543
0544 pr_info("Disabled Source: %s->%s->%s Ret %d\n",
0545 dev->active_source->name, dev->active_sink->name,
0546 dev->active_link_owner->name, ret);
0547
0548 dev->active_link = NULL;
0549 dev->active_link_owner = NULL;
0550 dev->active_source = NULL;
0551 dev->active_sink = NULL;
0552 dev->active_link_shared = false;
0553 dev->active_link_user = NULL;
0554 }
0555 }
0556 #endif
0557
0558 static int au0828_media_device_register(struct au0828_dev *dev,
0559 struct usb_device *udev)
0560 {
0561 #ifdef CONFIG_MEDIA_CONTROLLER
0562 int ret;
0563 struct media_entity *entity, *demod = NULL;
0564 struct media_link *link;
0565
0566 if (!dev->media_dev)
0567 return 0;
0568
0569 if (!media_devnode_is_registered(dev->media_dev->devnode)) {
0570
0571
0572 ret = media_device_register(dev->media_dev);
0573 if (ret) {
0574 media_device_delete(dev->media_dev, KBUILD_MODNAME,
0575 THIS_MODULE);
0576 dev->media_dev = NULL;
0577 dev_err(&udev->dev,
0578 "Media Device Register Error: %d\n", ret);
0579 return ret;
0580 }
0581 } else {
0582
0583
0584
0585
0586
0587
0588
0589 au0828_media_graph_notify(NULL, (void *) dev);
0590 }
0591
0592
0593
0594
0595
0596
0597
0598
0599
0600
0601
0602
0603 media_device_for_each_entity(entity, dev->media_dev) {
0604 switch (entity->function) {
0605 case MEDIA_ENT_F_TUNER:
0606 dev->tuner = entity;
0607 break;
0608 case MEDIA_ENT_F_ATV_DECODER:
0609 dev->decoder = entity;
0610 break;
0611 case MEDIA_ENT_F_DTV_DEMOD:
0612 demod = entity;
0613 break;
0614 }
0615 }
0616
0617
0618 if (dev->tuner) {
0619 list_for_each_entry(link, &dev->tuner->links, list) {
0620 if (demod && link->sink->entity == demod)
0621 media_entity_setup_link(link, 0);
0622 if (dev->decoder && link->sink->entity == dev->decoder)
0623 media_entity_setup_link(link, 0);
0624 }
0625 }
0626
0627
0628 dev->entity_notify.notify_data = (void *) dev;
0629 dev->entity_notify.notify = (void *) au0828_media_graph_notify;
0630 ret = media_device_register_entity_notify(dev->media_dev,
0631 &dev->entity_notify);
0632 if (ret) {
0633 dev_err(&udev->dev,
0634 "Media Device register entity_notify Error: %d\n",
0635 ret);
0636 return ret;
0637 }
0638
0639 mutex_lock(&dev->media_dev->graph_mutex);
0640 dev->media_dev->source_priv = (void *) dev;
0641 dev->media_dev->enable_source = au0828_enable_source;
0642 dev->media_dev->disable_source = au0828_disable_source;
0643 mutex_unlock(&dev->media_dev->graph_mutex);
0644 #endif
0645 return 0;
0646 }
0647
0648 static int au0828_usb_probe(struct usb_interface *interface,
0649 const struct usb_device_id *id)
0650 {
0651 int ifnum;
0652 int retval = 0;
0653
0654 struct au0828_dev *dev;
0655 struct usb_device *usbdev = interface_to_usbdev(interface);
0656
0657 ifnum = interface->altsetting->desc.bInterfaceNumber;
0658
0659 if (ifnum != 0)
0660 return -ENODEV;
0661
0662 dprintk(1, "%s() vendor id 0x%x device id 0x%x ifnum:%d\n", __func__,
0663 le16_to_cpu(usbdev->descriptor.idVendor),
0664 le16_to_cpu(usbdev->descriptor.idProduct),
0665 ifnum);
0666
0667
0668
0669
0670
0671
0672 if (usbdev->speed != USB_SPEED_HIGH && disable_usb_speed_check == 0) {
0673 pr_err("au0828: Device initialization failed.\n");
0674 pr_err("au0828: Device must be connected to a high-speed USB 2.0 port.\n");
0675 return -ENODEV;
0676 }
0677
0678 dev = kzalloc(sizeof(*dev), GFP_KERNEL);
0679 if (dev == NULL) {
0680 pr_err("%s() Unable to allocate memory\n", __func__);
0681 return -ENOMEM;
0682 }
0683
0684 mutex_init(&dev->lock);
0685 mutex_lock(&dev->lock);
0686 mutex_init(&dev->mutex);
0687 mutex_init(&dev->dvb.lock);
0688 dev->usbdev = usbdev;
0689 dev->boardnr = id->driver_info;
0690 dev->board = au0828_boards[dev->boardnr];
0691
0692
0693 retval = au0828_media_device_init(dev, usbdev);
0694 if (retval) {
0695 pr_err("%s() au0828_media_device_init failed\n",
0696 __func__);
0697 mutex_unlock(&dev->lock);
0698 kfree(dev);
0699 return retval;
0700 }
0701
0702 retval = au0828_v4l2_device_register(interface, dev);
0703 if (retval) {
0704 au0828_usb_v4l2_media_release(dev);
0705 mutex_unlock(&dev->lock);
0706 kfree(dev);
0707 return retval;
0708 }
0709
0710
0711 au0828_write(dev, REG_600, 1 << 4);
0712
0713
0714 au0828_gpio_setup(dev);
0715
0716
0717 au0828_i2c_register(dev);
0718
0719
0720 au0828_card_setup(dev);
0721
0722
0723
0724
0725
0726 usb_set_intfdata(interface, dev);
0727
0728
0729 retval = au0828_analog_register(dev, interface);
0730 if (retval) {
0731 pr_err("%s() au0828_analog_register failed to register on V4L2\n",
0732 __func__);
0733 mutex_unlock(&dev->lock);
0734 goto done;
0735 }
0736
0737
0738 retval = au0828_dvb_register(dev);
0739 if (retval)
0740 pr_err("%s() au0828_dvb_register failed\n",
0741 __func__);
0742
0743
0744 au0828_rc_register(dev);
0745
0746 pr_info("Registered device AU0828 [%s]\n",
0747 dev->board.name == NULL ? "Unset" : dev->board.name);
0748
0749 mutex_unlock(&dev->lock);
0750
0751 retval = au0828_media_device_register(dev, usbdev);
0752
0753 done:
0754 if (retval < 0)
0755 au0828_usb_disconnect(interface);
0756
0757 return retval;
0758 }
0759
0760 static int au0828_suspend(struct usb_interface *interface,
0761 pm_message_t message)
0762 {
0763 struct au0828_dev *dev = usb_get_intfdata(interface);
0764
0765 if (!dev)
0766 return 0;
0767
0768 pr_info("Suspend\n");
0769
0770 au0828_rc_suspend(dev);
0771 au0828_v4l2_suspend(dev);
0772 au0828_dvb_suspend(dev);
0773
0774
0775
0776 return 0;
0777 }
0778
0779 static int au0828_resume(struct usb_interface *interface)
0780 {
0781 struct au0828_dev *dev = usb_get_intfdata(interface);
0782 if (!dev)
0783 return 0;
0784
0785 pr_info("Resume\n");
0786
0787
0788 au0828_write(dev, REG_600, 1 << 4);
0789
0790
0791 au0828_gpio_setup(dev);
0792
0793 au0828_rc_resume(dev);
0794 au0828_v4l2_resume(dev);
0795 au0828_dvb_resume(dev);
0796
0797
0798
0799 return 0;
0800 }
0801
0802 static struct usb_driver au0828_usb_driver = {
0803 .name = KBUILD_MODNAME,
0804 .probe = au0828_usb_probe,
0805 .disconnect = au0828_usb_disconnect,
0806 .id_table = au0828_usb_id_table,
0807 .suspend = au0828_suspend,
0808 .resume = au0828_resume,
0809 .reset_resume = au0828_resume,
0810 };
0811
0812 static int __init au0828_init(void)
0813 {
0814 int ret;
0815
0816 if (au0828_debug & 1)
0817 pr_info("%s() Debugging is enabled\n", __func__);
0818
0819 if (au0828_debug & 2)
0820 pr_info("%s() USB Debugging is enabled\n", __func__);
0821
0822 if (au0828_debug & 4)
0823 pr_info("%s() I2C Debugging is enabled\n", __func__);
0824
0825 if (au0828_debug & 8)
0826 pr_info("%s() Bridge Debugging is enabled\n",
0827 __func__);
0828
0829 if (au0828_debug & 16)
0830 pr_info("%s() IR Debugging is enabled\n",
0831 __func__);
0832
0833 pr_info("au0828 driver loaded\n");
0834
0835 ret = usb_register(&au0828_usb_driver);
0836 if (ret)
0837 pr_err("usb_register failed, error = %d\n", ret);
0838
0839 return ret;
0840 }
0841
0842 static void __exit au0828_exit(void)
0843 {
0844 usb_deregister(&au0828_usb_driver);
0845 }
0846
0847 module_init(au0828_init);
0848 module_exit(au0828_exit);
0849
0850 MODULE_DESCRIPTION("Driver for Auvitek AU0828 based products");
0851 MODULE_AUTHOR("Steven Toth <stoth@linuxtv.org>");
0852 MODULE_LICENSE("GPL");
0853 MODULE_VERSION("0.0.3");